// This code is in the public domain -- castanyo@yahoo.es #ifndef NV_MATH_RANDOM_H #define NV_MATH_RANDOM_H #include // nextPowerOfTwo #include namespace nv { /// Interface of the random number generators. class Rand { public: virtual ~Rand() {} enum time_e { Time }; /// Provide a new seed. virtual void seed( uint s ) { /* empty */ }; /// Get an integer random number. virtual uint get() = 0; /// Get a random number on [0, max] interval. uint getRange( uint max ) { uint n; // uint mask = Bitmask( max ); // do { n = Get() & mask; } while( n > max ); uint np2 = nextPowerOfTwo( max ); do { n = get() & (np2-1); } while( n > max ); return n; } /// Random number on [0.0, 1.0] interval. float getFloat() { union { uint32 i; float f; } pun; pun.i = 0x3f800000UL | (get() & 0x007fffffUL); return pun.f - 1.0f; } /* /// Random number on [0.0, 1.0] interval. double getReal() { return double(get()) * (1.0/4294967295.0); // 2^32-1 } /// Random number on [0.0, 1.0) interval. double getRealExclusive() { return double(get()) * (1.0/4294967296.0); // 2^32 } */ /// Get the max value of the random number. uint max() const { return 4294967295U; } // Get a random seed. static uint randomSeed(); }; /// Very simple random number generator with low storage requirements. class SimpleRand : public Rand { public: /// Constructor that uses the current time as the seed. SimpleRand( time_e ) { seed(randomSeed()); } /// Constructor that uses the given seed. SimpleRand( uint s = 0 ) { seed(s); } /// Set the given seed. virtual void seed( uint s ) { current = s; } /// Get a random number. virtual uint get() { return current = current * 1103515245 + 12345; } private: uint current; }; /// Mersenne twister random number generator. class MTRand : public Rand { public: enum { N = 624 }; // length of state vector enum { M = 397 }; /// Constructor that uses the current time as the seed. MTRand( time_e ) { seed(randomSeed()); } /// Constructor that uses the given seed. MTRand( uint s = 0 ) { seed(s); } /// Constructor that uses the given seeds. NVMATH_API MTRand( const uint * seed_array, uint length ); /// Provide a new seed. virtual void seed( uint s ) { initialize(s); reload(); } /// Get a random number between 0 - 65536. virtual uint get() { // Pull a 32-bit integer from the generator state // Every other access function simply transforms the numbers extracted here if( left == 0 ) { reload(); } left--; uint s1; s1 = *next++; s1 ^= (s1 >> 11); s1 ^= (s1 << 7) & 0x9d2c5680U; s1 ^= (s1 << 15) & 0xefc60000U; return ( s1 ^ (s1 >> 18) ); }; private: NVMATH_API void initialize( uint32 seed ); NVMATH_API void reload(); uint hiBit( uint u ) const { return u & 0x80000000U; } uint loBit( uint u ) const { return u & 0x00000001U; } uint loBits( uint u ) const { return u & 0x7fffffffU; } uint mixBits( uint u, uint v ) const { return hiBit(u) | loBits(v); } uint twist( uint m, uint s0, uint s1 ) const { return m ^ (mixBits(s0,s1)>>1) ^ ((~loBit(s1)+1) & 0x9908b0dfU); } private: uint state[N]; // internal state uint * next; // next value to get from state int left; // number of values left before reload needed }; /** George Marsaglia's random number generator. * Code based on Thatcher Ulrich public domain source code: * http://cvs.sourceforge.net/viewcvs.py/tu-testbed/tu-testbed/base/tu_random.cpp?rev=1.7&view=auto * * PRNG code adapted from the complimentary-multiply-with-carry * code in the article: George Marsaglia, "Seeds for Random Number * Generators", Communications of the ACM, May 2003, Vol 46 No 5, * pp90-93. * * The article says: * * "Any one of the choices for seed table size and multiplier will * provide a RNG that has passed extensive tests of randomness, * particularly those in [3], yet is simple and fast -- * approximately 30 million random 32-bit integers per second on a * 850MHz PC. The period is a*b^n, where a is the multiplier, n * the size of the seed table and b=2^32-1. (a is chosen so that * b is a primitive root of the prime a*b^n + 1.)" * * [3] Marsaglia, G., Zaman, A., and Tsang, W. Toward a universal * random number generator. _Statistics and Probability Letters * 8_ (1990), 35-39. */ class GMRand : public Rand { public: enum { SEED_COUNT = 8 }; // const uint64 a = 123471786; // for SEED_COUNT=1024 // const uint64 a = 123554632; // for SEED_COUNT=512 // const uint64 a = 8001634; // for SEED_COUNT=255 // const uint64 a = 8007626; // for SEED_COUNT=128 // const uint64 a = 647535442; // for SEED_COUNT=64 // const uint64 a = 547416522; // for SEED_COUNT=32 // const uint64 a = 487198574; // for SEED_COUNT=16 // const uint64 a = 716514398U; // for SEED_COUNT=8 enum { a = 716514398U }; GMRand( time_e ) { seed(randomSeed()); } GMRand(uint s = 987654321) { seed(s); } /// Provide a new seed. virtual void seed( uint s ) { c = 362436; i = SEED_COUNT - 1; for(int i = 0; i < SEED_COUNT; i++) { s = s ^ (s << 13); s = s ^ (s >> 17); s = s ^ (s << 5); Q[i] = s; } } /// Get a random number between 0 - 65536. virtual uint get() { const uint32 r = 0xFFFFFFFE; uint64 t; uint32 x; i = (i + 1) & (SEED_COUNT - 1); t = a * Q[i] + c; c = uint32(t >> 32); x = uint32(t + c); if( x < c ) { x++; c++; } uint32 val = r - x; Q[i] = val; return val; }; private: uint32 c; uint32 i; uint32 Q[8]; }; /** Random number implementation from the GNU Sci. Lib. (GSL). * Adapted from Nicholas Chapman version: * * Copyright (C) 1996, 1997, 1998, 1999, 2000 James Theiler, Brian Gough * This is the Unix rand48() generator. The generator returns the * upper 32 bits from each term of the sequence, * * x_{n+1} = (a x_n + c) mod m * * using 48-bit unsigned arithmetic, with a = 0x5DEECE66D , c = 0xB * and m = 2^48. The seed specifies the upper 32 bits of the initial * value, x_1, with the lower 16 bits set to 0x330E. * * The theoretical value of x_{10001} is 244131582646046. * * The period of this generator is ? FIXME (probably around 2^48). */ class Rand48 : public Rand { public: Rand48( time_e ) { seed(randomSeed()); } Rand48( uint s = 0x1234ABCD ) { seed(s); } /** Set the given seed. */ virtual void seed( uint s ) { vstate.x0 = 0x330E; vstate.x1 = uint16(s & 0xFFFF); vstate.x2 = uint16((s >> 16) & 0xFFFF); } /** Get a random number. */ virtual uint get() { advance(); uint x1 = vstate.x1; uint x2 = vstate.x2; return (x2 << 16) + x1; } private: void advance() { /* work with unsigned long ints throughout to get correct integer promotions of any unsigned short ints */ const uint32 x0 = vstate.x0; const uint32 x1 = vstate.x1; const uint32 x2 = vstate.x2; uint32 a; a = a0 * x0 + c0; vstate.x0 = uint16(a & 0xFFFF); a >>= 16; /* although the next line may overflow we only need the top 16 bits in the following stage, so it does not matter */ a += a0 * x1 + a1 * x0; vstate.x1 = uint16(a & 0xFFFF); a >>= 16; a += a0 * x2 + a1 * x1 + a2 * x0; vstate.x2 = uint16(a & 0xFFFF); } private: NVMATH_API static const uint16 a0, a1, a2, c0; struct rand48_state_t { uint16 x0, x1, x2; } vstate; }; } // nv namespace #endif // NV_MATH_RANDOM_H