📄 mtwist.c
字号:
* corresponding decimal constant. So we will compute the correct number at * run time as part of initialization, which will produce a nice exact * result. */double mt_32_to_double; /* Multiplier to convert long to dbl */double mt_64_to_double; /* Mult'r to cvt long long to dbl *//* * In the recurrence relation, the new value is XORed with MATRIX_A only if * the lower bit is nonzero. Since most modern machines don't like to * branch, it's vastly faster to handle this decision by indexing into an * array. The chosen bit is used as an index into the following vector, * which produces either zero or MATRIX_A and thus the desired effect. */static unsigned long matrix_decider[2] = {0x0, MATRIX_A};/* * Mark a PRNG's state as having been initialized. This is the only * way to set that field nonzero; that way we can be sure that the * constants are set properly before the PRNG is used. * * As a side effect, set up some constants that the PRNG assumes are * valid. These are calculated at initialization time rather than * being written as decimal constants because I frankly don't trust * the compiler's ASCII conversion routines. */void mts_mark_initialized( mt_state* state) /* State vector to mark initialized */ { int i; /* Power of 2 being calculated */ /* * Figure out the proper multiplier for long-to-double conversion. We * don't worry too much about efficiency, since the assumption is that * initialization is vastly rarer than generation of random numbers. */ mt_32_to_double = 1.0; for (i = 0; i < BIT_WIDTH; i++) mt_32_to_double /= 2.0; mt_64_to_double = mt_32_to_double; for (i = 0; i < BIT_WIDTH; i++) mt_64_to_double /= 2.0; state->initialized = 1; }/* * Initialize a Mersenne Twist PRNG from a 32-bit seed. * * According to Matsumoto and Nishimura's paper, the seed array needs to be * filled with nonzero values. (My own interpretation is that there needs * to be at least one nonzero value). They suggest using Knuth's PRNG from * Line 25, Table 1, p.102, "The Art of Computer Programming," Vol. 2 (2nd * ed.), 1981. I find that rather odd, since that particular PRNG is * sensitive to having an initial seed of zero (there are many other PRNGs * out there that have an additive component, so that a seed of zero does * not generate a repeating-zero sequence). However, one thing I learned * from reading Knuth is that you shouldn't second-guess mathematicians * about PRNGs. Also, by following M & N's approach, we will be compatible * with other implementations. So I'm going to stick with their version, * with the single addition that a zero seed will be changed to their * default seed. */void mts_seed32( mt_state* state, /* State vector to initialize */ unsigned long seed) /* 32-bit seed to start from */ { int i; /* Loop index */ if (seed == 0) seed = DEFAULT_SEED32_OLD; /* * Fill the state vector using Knuth's PRNG. Be sure to mask down * to 32 bits in case we're running on a machine with 64-bit * longs. */ state->statevec[MT_STATE_SIZE - 1] = seed & 0xffffffff; for (i = MT_STATE_SIZE - 2; i >= 0; i--) state->statevec[i] = (KNUTH_MULTIPLIER_OLD * state->statevec[i + 1]) & 0xffffffff; state->stateptr = MT_STATE_SIZE; mts_mark_initialized(state); /* * Matsumoto and Nishimura's implementation refreshes the PRNG * immediately after running the Knuth algorithm. This is * probably a good thing, since Knuth's PRNG doesn't generate very * good numbers. */ mts_refresh(state); }/* * Initialize a Mersenne Twist PRNG from a 32-bit seed, using * Matsumoto and Nishimura's newer reference implementation (Jan. 9, * 2002). */void mts_seed32new( mt_state* state, /* State vector to initialize */ unsigned long seed) /* 32-bit seed to start from */ { int i; /* Loop index */ unsigned long nextval; /* Next value being calculated */ /* * Fill the state vector using Knuth's PRNG. Be sure to mask down * to 32 bits in case we're running on a machine with 64-bit * longs. */ state->statevec[MT_STATE_SIZE - 1] = seed & 0xffffffffUL; for (i = MT_STATE_SIZE - 2; i >= 0; i--) { nextval = state->statevec[i + 1] >> KNUTH_SHIFT; nextval ^= state->statevec[i + 1]; nextval *= KNUTH_MULTIPLIER_NEW; nextval += (MT_STATE_SIZE - 1) - i; state->statevec[i] = nextval & 0xffffffffUL; } state->stateptr = MT_STATE_SIZE; mts_mark_initialized(state); /* * Matsumoto and Nishimura's implementation refreshes the PRNG * immediately after running the Knuth algorithm. This is * probably a good thing, since Knuth's PRNG doesn't generate very * good numbers. */ mts_refresh(state); }/* * Initialize a Mersenne Twist RNG from a 624-long seed. * * The 32-bit seeding routine given by Matsumoto and Nishimura has the * drawback that there are only 2^32 different PRNG sequences that can be * generated by calling that function. This function solves that problem by * allowing a full 624*32-bit state to be given. (Note that 31 bits of the * given state are ignored; see the paper for details.) * * Since an all-zero state would cause the PRNG to cycle, we detect * that case and abort the program (silently, since there is no * portable way to produce a message in both C and C++ environments). * An alternative would be to artificially force the state to some * known nonzero value. However, I feel that if the user is providing * a full state, it's a bug to provide all zeros and we we shouldn't * conceal the bug by generating apparently correct output. */void mts_seedfull( mt_state* state, /* State vector to initialize */ unsigned long seeds[MT_STATE_SIZE]) /* Seed array to start from */ { int had_nz = 0; /* NZ if at least one NZ seen */ int i; /* Loop index */ for (i = 0; i < MT_STATE_SIZE; i++) { if (seeds[i] != 0) had_nz = 1; state->statevec[MT_STATE_SIZE - i - 1] = seeds[i]; } if (!had_nz) { /* * It would be nice to abort with a message. Unfortunately, fprintf * isn't compatible with all implementations of C++. In the * interest of C++ compatibility, therefore, we will simply abort * silently. It will unfortunately be up to a programmer to run * under a debugger (or examine the core dump) to discover the cause * of the abort. */ abort(); } state->stateptr = MT_STATE_SIZE; mts_mark_initialized(state); }/* * Choose a seed based on some moderately random input. Prefers * /dev/urandom as a source of random numbers, but uses the lower bits * of the current time if /dev/urandom is not available. In any case, * only provides 32 bits of entropy. */void mts_seed( mt_state* state) /* State vector to seed */ { mts_devseed(state, DEVURANDOM); }/* * Choose a seed based on some fairly random input. Prefers * /dev/random as a source of random numbers, but uses the lower bits * of the current time if /dev/random is not available. In any case, * only provides 32 bits of entropy. */void mts_goodseed( mt_state* state) /* State vector to seed */ { mts_devseed(state, DEVRANDOM); }/* * Choose a seed based on a random-number device given by the caller. * If that device can't be opened, use the lower 32 bits from the * current time. */static void mts_devseed( mt_state* state, /* State vector to seed */ char* seed_dev) /* Device to seed from */ { int bytesread; /* Byte count read from device */ int nextbyte; /* Index of next byte to read */ FILE* ranfile; /* Access to device */ union { char ranbuffer[sizeof (unsigned long)]; /* Space for reading random int */ unsigned long randomvalue; /* Random value for initialization */ } randomunion; /* Union for reading random int */#ifdef WIN32 struct _timeb tb; /* Time of day (Windows mode) */#else /* WIN32 */ struct timeval tv; /* Time of day */ struct timezone tz; /* Dummy for gettimeofday */#endif /* WIN32 */ ranfile = fopen(seed_dev, "rb"); if (ranfile != NULL) { for (nextbyte = 0; nextbyte < (int)sizeof randomunion.ranbuffer; nextbyte += bytesread) { bytesread = fread(&randomunion.ranbuffer[nextbyte], 1, sizeof randomunion.ranbuffer - nextbyte, ranfile); if (bytesread == 0) break; } fclose(ranfile); if (nextbyte == sizeof randomunion.ranbuffer) { mts_seed32new(state, randomunion.randomvalue); return; } } /* * The device isn't available. Use the time. We will * assume that the time of day is accurate to microsecond * resolution, which is true on most modern machines. */#ifdef WIN32 (void) _ftime (&tb);#else /* WIN32 */ (void) gettimeofday (&tv, &tz);#endif /* WIN32 */ /* * We just let the excess part of the seconds field overflow */#ifdef WIN32 randomunion.randomvalue = tb.time * 1000 + tb.millitm;#else /* WIN32 */ randomunion.randomvalue = tv.tv_sec * 1000000 + tv.tv_usec;#endif /* WIN32 */ mts_seed32new(state, randomunion.randomvalue); }/* * Choose a seed based on the best random input available. Prefers * /dev/random as a source of random numbers, and reads the entire * 624-long state from that device. Because of this approach, the * function can take a long time (in real time) to complete, since * /dev/random may have to wait quite a while before it can provide * that much randomness. If /dev/random is unavailable, falls back to * calling mts_goodseed. */void mts_bestseed( mt_state* state) /* State vector to seed */ { int bytesread; /* Byte count read from device */ int nextbyte; /* Index of next byte to read */ FILE* ranfile; /* Access to device */ ranfile = fopen("/dev/random", "rb"); if (ranfile == NULL) { mts_goodseed(state); return; } for (nextbyte = 0; nextbyte < (int)sizeof state->statevec; nextbyte += bytesread) { bytesread = fread((char *)&state->statevec + nextbyte, 1, sizeof state->statevec - nextbyte, ranfile); if (bytesread == 0) { /* * Something went wrong. Fall back to time-based seeding. */ fclose(ranfile); mts_goodseed(state); return; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -