📄 mtwist.h
字号:
#ifndef MTWIST_H#define MTWIST_H/* * $Id: mtwist.h,v 1.15 2003/09/11 23:56:20 geoff Exp geoff $ * * Header file for C/C++ use of the Mersenne-Twist pseudo-RNG. See * http://www.math.keio.ac.jp/~matumoto/emt.html for full information. * * Author of this header file: Geoffrey H. Kuenning, March 18, 2001. * * IMPORTANT NOTE: the Makefile must define two machine-specific * variables to get optimum features and performance: * * MT_NO_INLINE should be defined if the compiler doesn't support * the "inline" keyword. * MT_NO_LONGLONG should be defined if the compiler doesn't support a * "long long" type for 64-bit integers * MT_MACHINE_BITS must be either 32 or 64, reflecting the natural * size of the processor registers. If undefined, it * will default to a value calculated from limits.h. * * The first two variables above are defined in an inverted sense * because I expect that most compilers will support inline and * long-long. By inverting the sense, this common case will require * no special compiler flags. * * IMPORTANT NOTE: this software assumes that the inherent width of a * "long" is 32 bits. If you are running on a machine that uses * 64-bit longs, some of the declarations and code will have to be * modified. * * The executable part of this software is based on LGPL-ed code by * Takuji Nishimura. The header file is therefore also distributed * under the LGPL: * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. You should have * received a copy of the GNU Library General Public License along * with this library; if not, write to the Free Foundation, Inc., 59 * Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Log: mtwist.h,v $ * Revision 1.15 2003/09/11 23:56:20 geoff * Allow stdio references in C++ files; it turns out that ANSI has * blessed it. Declare the various functions as external even if they're * inlined or being compiled directly (in mtwist.c). Get rid of a #ifdef * that can't ever be true. * * Revision 1.14 2003/09/11 05:50:53 geoff * Don't allow stdio references from C++, since they're not guaranteed to * work on all compilers. Disable inlining using the MT_INLINE keyword * rather than #defining inline, since doing the latter can affect other * files and functions than our own. * * Revision 1.13 2003/07/01 23:29:29 geoff * Refer to streams from the standard library using the correct namespace. * * Revision 1.12 2002/10/30 07:39:54 geoff * Declare the new seeding functions. * * Revision 1.11 2001/06/19 00:41:16 geoff * For consistency with other C++ types, don't put out a newline after * the saved data. * * Revision 1.10 2001/06/18 10:09:24 geoff * Fix some places where I forgot to set one of the result values. Make * the C++ state vector protected so the random-distributions package can * pass it to the C functions. * * Revision 1.9 2001/06/18 05:40:12 geoff * Prefix the compile options with MT_. * * Revision 1.8 2001/06/14 10:26:59 geoff * Invert the sense of the #define flags so that the default is the * normal case (if gcc is normal!). Also default MT_MACHINE_BITS to 32. * * Revision 1.7 2001/06/14 10:10:38 geoff * Move the critical-path PRNG code into the header file so that it can * be inlined. Add saving/loading of state. Add functions to seed based * on /dev/random or the time. Add the function-call operator in the C++ * code. * * Revision 1.6 2001/06/11 10:00:04 geoff * Add declarations of the refresh and /dev/random seeding functions. * Change getstate to return a complete state pointer, since knowing the * position in the state vector is critical to restoring the state. * * Revision 1.5 2001/04/23 08:36:03 geoff * Remember to zero the state pointer when constructing, since otherwise * proper initialization won't happen. * * Revision 1.4 2001/04/14 01:33:32 geoff * Clarify the license * * Revision 1.3 2001/04/14 01:04:54 geoff * Add a C++ class, mt_prng, that makes usage more convenient for C++ * programmers. * * Revision 1.2 2001/04/09 08:45:00 geoff * Fix the name in the #ifndef wrapper, and clean up some outdated comments. * * Revision 1.1 2001/04/07 09:43:41 geoff * Initial revision * */#include <stdio.h>#ifdef __cplusplus#include <iostream>#endif /* __cplusplus */#ifndef MT_MACHINE_BITS#include <limits.h>#if INT_MAX == 2147483647#define MT_MACHINE_BITS 32#else /* INT_MAX */#define MT_MACHINE_BITS 64#endif /* INT_MAX */#endif /* MT_MACHINE_BITS *//* * The following value is a fundamental parameter of the algorithm. * It was found experimentally using methods described in Matsumoto * and Nishimura's paper. It is exceedingly magic; don't change it. */#define MT_STATE_SIZE 624 /* Size of the MT state vector *//* * Internal state for an MT RNG. The user can keep multiple mt_state * structures around as a way of generating multiple streams of random * numbers. * * In Matsumoto and Nishimura's original paper, the state vector was * processed in a forward direction. I have reversed the state vector * in this implementation. The reason for the reversal is that it * allows the critical path to use a test against zero instead of a * test against 624 to detect the need to refresh the state. on most * machines, testing against zero is slightly faster. It also means * that a state that has been set to all zeros will be correctly * detected as needing initialization; this means that setting a state * vector to zero (either with memset or by statically allocating it) * will cause the RNG to operate properly. */typedef struct { unsigned long statevec[MT_STATE_SIZE]; /* Vector holding current state */ int stateptr; /* Next state entry to be used */ int initialized; /* NZ if state was initialized */ } mt_state;#ifdef __cplusplusextern "C" {#endif/* * Functions for manipulating any generator (given a state pointer). */extern void mts_mark_initialized(mt_state* state); /* Mark a PRNG state as initialized */extern void mts_seed32(mt_state* state, unsigned long seed); /* Set random seed for any generator */extern void mts_seed32new(mt_state* state, unsigned long seed); /* Set random seed for any generator */extern void mts_seedfull(mt_state* state, unsigned long seeds[MT_STATE_SIZE]); /* Set complicated seed for any gen. */extern void mts_seed(mt_state* state); /* Choose seed from random input. */ /* ..Prefers /dev/urandom; uses time */ /* ..if /dev/urandom unavailable. */ /* ..Only gives 32 bits of entropy. */extern void mts_goodseed(mt_state* state); /* Choose seed from more random */ /* ..input than mts_seed. Prefers */ /* ../dev/random; uses time if that */ /* ..is unavailable. Only gives 32 */ /* ..bits of entropy. */extern void mts_bestseed(mt_state* state); /* Choose seed from extremely random */ /* ..input (can be *very* slow). */ /* ..Prefers /dev/random and reads */ /* ..the entire state from there. */ /* ..If /dev/random is unavailable, */ /* ..falls back to mt_goodseed(). */ /* ..Not usually worth the cost. */extern void mts_refresh(mt_state* state); /* Generate 624 more random values */extern int mts_savestate(FILE* statefile, mt_state* state); /* Save state to a file (ASCII). */ /* ..Returns NZ if succeeded. */extern int mts_loadstate(FILE* statefile, mt_state* state); /* Load state from a file (ASCII). */ /* ..Returns NZ if succeeded. *//* * Functions for manipulating the default generator. */extern void mt_seed32(unsigned long seed); /* Set random seed for default gen. */extern void mt_seed32new(unsigned long seed); /* Set random seed for default gen. */extern void mt_seedfull(unsigned long seeds[MT_STATE_SIZE]); /* Set complicated seed for default */extern void mt_seed(void); /* Choose seed from random input. */ /* ..Prefers /dev/urandom; uses time */ /* ..if /dev/urandom unavailable. */ /* ..Only gives 32 bits of entropy. */extern void mt_goodseed(void); /* Choose seed from more random */ /* ..input than mts_seed. Prefers */ /* ../dev/random; uses time if that */ /* ..is unavailable. Only gives 32 */ /* ..bits of entropy. */extern void mt_bestseed(void); /* Choose seed from extremely random */ /* ..input (can be *very* slow). */ /* ..Prefers /dev/random and reads */ /* ..the entire state from there. */ /* ..If /dev/random is unavailable, */ /* ..falls back to mt_goodseed(). */ /* ..Not usually worth the cost. */extern mt_state* mt_getstate(void); /* Get current state of default */ /* ..generator */extern int mt_savestate(FILE* statefile); /* Save state to a file (ASCII) */ /* ..Returns NZ if succeeded. */extern int mt_loadstate(FILE* statefile); /* Load state from a file (ASCII) */ /* ..Returns NZ if succeeded. */#ifdef __cplusplus }#endif/* * Functions for generating random numbers. The actual code of the * functions is given in this file so that it can be declared inline. * For compilers that don't have the inline feature, mtwist.c will * incorporate this file with some clever #defining so that the code * actually gets compiled. In that case, however, "extern" * definitions will be needed here, so we give them. */#ifdef __cplusplus#undef MT_NO_INLINE /* C++ definitely has inlining */#endif /* __cplusplus */extern unsigned long mts_lrand(mt_state* state); /* Generate 32-bit value, any gen. */#ifndef MT_NO_LONGLONGextern unsigned long long mts_llrand(mt_state* state); /* Generate 64-bit value, any gen. */#endif /* MT_NO_LONGLONG */extern double mts_drand(mt_state* state); /* Generate floating value, any gen. */ /* Fast, with only 32-bit precision */extern double mts_ldrand(mt_state* state); /* Generate floating value, any gen. */ /* Slower, with 64-bit precision */extern unsigned long mt_lrand(void); /* Generate 32-bit random value */#ifndef MT_NO_LONGLONGextern unsigned long long mt_llrand(void); /* Generate 64-bit random value */#endif /* MT_NO_LONGLONG */extern double mt_drand(void); /* Generate floating value */ /* Fast, with only 32-bit precision */extern double mt_ldrand(void); /* Generate floating value */ /* Slower, with 64-bit precision */#ifndef MT_NO_INLINE/* * Tempering parameters. These are perhaps the most magic of all the magic * values in the algorithm. The values are again experimentally determined. * The values generated by the recurrence relation (constants above) are not * equidistributed in 623-space. For some reason, the tempering process * produces that effect. Don't ask me why. Read the paper if you can * understand the math. Or just trust these magic numbers. */#define MT_TEMPERING_MASK_B 0x9d2c5680#define MT_TEMPERING_MASK_C 0xefc60000#define MT_TEMPERING_SHIFT_U(y) \ (y >> 11)#define MT_TEMPERING_SHIFT_S(y) \ (y << 7)#define MT_TEMPERING_SHIFT_T(y) \ (y << 15)#define MT_TEMPERING_SHIFT_L(y) \ (y >> 18)/* * Macros to do the tempering. MT_PRE_TEMPER does all but the last step; * it's useful for situations where the final step can be incorporated * into a return statement. MT_FINAL_TEMPER does that final step (not as * an assignment). MT_TEMPER does the entire process. Note that * MT_PRE_TEMPER and MT_TEMPER both modify their arguments. */#define MT_PRE_TEMPER(value) \ do \ { \ value ^= MT_TEMPERING_SHIFT_U(value); \ value ^= MT_TEMPERING_SHIFT_S(value) & MT_TEMPERING_MASK_B; \ value ^= MT_TEMPERING_SHIFT_T(value) & MT_TEMPERING_MASK_C; \ } \ while (0)#define MT_FINAL_TEMPER(value) \ ((value) ^ MT_TEMPERING_SHIFT_L(value))#define MT_TEMPER(value) \ do \ { \ value ^= MT_TEMPERING_SHIFT_U(value); \ value ^= MT_TEMPERING_SHIFT_S(value) & MT_TEMPERING_MASK_B; \ value ^= MT_TEMPERING_SHIFT_T(value) & MT_TEMPERING_MASK_C; \ value ^= MT_TEMPERING_SHIFT_L(value); \ } \ while (0)extern mt_state mt_default_state; /* State of the default generator */extern double mt_32_to_double; /* Multiplier to convert long to dbl */extern double mt_64_to_double; /* Mult'r to cvt long long to dbl *//* * In gcc, inline functions must be declared extern or they'll produce * assembly code (and thus linking errors). We have to work around * that difficulty with the MT_EXTERN define. */#ifndef MT_EXTERN#ifdef __cplusplus#define MT_EXTERN /* C++ doesn't need static */#else /* __cplusplus */#define MT_EXTERN extern /* C (at least gcc) needs extern */#endif /* __cplusplus */#endif /* MT_EXTERN *//* * Make it possible for mtwist.c to disable the inline keyword. We * use our own keyword so that we don't interfere with inlining in * C/C++ header files, above. */#ifndef MT_INLINE#define MT_INLINE inline /* Compiler has inlining */#endif /* MT_INLINE *//* * Generate a random number in the range 0 to 2^32-1, inclusive, working * from a given state vector. * * The generator is optimized for speed. The primary optimization is that * the pseudorandom numbers are generated in batches of MT_STATE_SIZE. This * saves the cost of a modulus operation in the critical path. */MT_EXTERN MT_INLINE unsigned long mts_lrand( register mt_state* state) /* State for the PRNG */ { register unsigned long random_value; /* Pseudorandom value generated */ if (state->stateptr <= 0) mts_refresh(state); random_value = state->statevec[--state->stateptr]; MT_PRE_TEMPER(random_value); return MT_FINAL_TEMPER(random_value); }#ifndef MT_NO_LONGLONG/* * Generate a random number in the range 0 to 2^64-1, inclusive, working * from a given state vector. * * According to Matsumoto and Nishimura, such a number can be generated by * simply concatenating two 32-bit pseudorandom numbers. Who am I to argue? * * Note that there is a slight inefficiency here: if the 624-entry state is * recycled on the second call to mts_lrand, there will be an unnecessary * check to see if the state has been initialized. The cost of that check * seems small (since it happens only once every 624 random numbers, and * never if only 64-bit numbers are being generated), so I didn't bother to * optimize it out. Doing so would be messy, since it would require two * nearly-identical internal implementations of mts_lrand. */MT_EXTERN MT_INLINE unsigned long long mts_llrand( register mt_state* state) /* State for the PRNG */ { register unsigned long random_value_1; /* 1st pseudorandom value generated */ register unsigned long random_value_2; /* 2nd pseudorandom value generated */ /* * For maximum speed, we'll handle the two overflow cases * together. That will save us one test in the common case, at * the expense of an extra one in the overflow case. */ if (--state->stateptr <= 0) { if (state->stateptr < 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -