Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

MersenneTwister.h

Go to the documentation of this file.
00001 // MersenneTwister.h
00002 // Mersenne Twister random number generator -- a C++ class MTRand
00003 // Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
00004 // Richard J. Wagner  v0.8  24 March 2002  rjwagner@writeme.com
00005 
00006 // The Mersenne Twister is an algorithm for generating random numbers.  It
00007 // was designed with consideration of the flaws in various other generators.
00008 // The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
00009 // are far greater.  The generator is also fast; it avoids multiplication and
00010 // division, and it benefits from caches and pipelines.  For more information
00011 // see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html
00012 
00013 // Reference
00014 // M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally
00015 // Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on
00016 // Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30.
00017 
00018 // Copyright (C) 2002  Richard J. Wagner
00019 // 
00020 // This library is free software; you can redistribute it and/or
00021 // modify it under the terms of the GNU Lesser General Public
00022 // License as published by the Free Software Foundation; either
00023 // version 2.1 of the License, or (at your option) any later version.
00024 // 
00025 // This library is distributed in the hope that it will be useful,
00026 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00027 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00028 // Lesser General Public License for more details.
00029 // 
00030 // You should have received a copy of the GNU Lesser General Public
00031 // License along with this library; if not, write to the Free Software
00032 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00033 
00034 // The original code included the following notice:
00035 //
00036 //     Copyright (C) 1997, 1999 Makoto Matsumoto and Takuji Nishimura.
00037 //     When you use this, send an email to: matumoto@math.keio.ac.jp
00038 //     with an appropriate reference to your work.
00039 //
00040 // It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu
00041 // when you write.
00042 
00043 #ifndef MERSENNETWISTER_H
00044 #define MERSENNETWISTER_H
00045 
00046 // Not thread safe (unless auto-initialization is avoided and each thread has
00047 // its own MTRand object)
00048 
00049 #include <iostream>
00050 #include <limits.h>
00051 #include <stdio.h>
00052 #include <time.h>
00053 
00054 class MTRand {
00055 // Data
00056 public:
00057         typedef unsigned long uint32;  // unsigned integer type, at least 32 bits
00058         
00059         enum { N = 624 };              // length of state vector
00060         enum { SAVE = N + 1 };         // length of array for save()
00061 
00062 protected:
00063         enum { M = 397 };              // period parameter
00064         enum { MAGIC = 0x9908b0dfU };  // magic constant
00065         
00066         uint32 state[N];  // internal state
00067         uint32 *pNext;    // next value to get from state
00068         int left;         // number of values left before reload needed
00069 
00070 
00071 //Methods
00072 public:
00073         MTRand( const uint32& oneSeed );  // initialize with a simple uint32
00074         MTRand( uint32 *const bigSeed );  // initialize with an array of N uint32's
00075         MTRand();  // auto-initialize with /dev/urandom or time() and clock()
00076         
00077         // Access to 32-bit random numbers
00078         // Do NOT use for CRYPTOGRAPHY without securely hashing several returned
00079         // values together, otherwise the generator state can be learned after
00080         // reading 624 consecutive values.
00081         double rand();                          // real number in [0,1]
00082         double rand( const double& n );         // real number in [0,n]
00083         double randExc();                       // real number in [0,1)
00084         double randExc( const double& n );      // real number in [0,n)
00085         double randDblExc();                    // real number in (0,1)
00086         double randDblExc( const double& n );   // real number in (0,n)
00087         uint32 randInt();                       // integer in [0,2^32-1]
00088         uint32 randInt( const uint32& n );      // integer in [0,n] for n < 2^32
00089         double operator()() { return rand(); }  // same as rand()
00090         
00091         // Re-seeding functions with same behavior as initializers
00092         void seed( uint32 oneSeed );
00093         void seed( uint32 *const bigSeed );
00094         void seed();
00095         
00096         // Saving and loading generator state
00097         void save( uint32* saveArray ) const;  // to array of size SAVE
00098         void load( uint32 *const loadArray );  // from such array
00099         friend std::ostream& operator<<( std::ostream& os, const MTRand& mtrand );
00100         friend std::istream& operator>>( std::istream& is, MTRand& mtrand );
00101 
00102 protected:
00103         void reload();
00104         uint32 hiBit( const uint32& u ) const { return u & 0x80000000U; }
00105         uint32 loBit( const uint32& u ) const { return u & 0x00000001U; }
00106         uint32 loBits( const uint32& u ) const { return u & 0x7fffffffU; }
00107         uint32 mixBits( const uint32& u, const uint32& v ) const
00108                 { return hiBit(u) | loBits(v); }
00109         uint32 twist( const uint32& m, const uint32& s0, const uint32& s1 ) const
00110                 { return m ^ (mixBits(s0,s1)>>1) ^ (loBit(s1) ? MAGIC : 0U); }
00111         static uint32 hash( time_t t, clock_t c );
00112 };
00113 
00114 
00115 inline MTRand::MTRand( const uint32& oneSeed )
00116         { seed(oneSeed); }
00117 
00118 inline MTRand::MTRand( uint32 *const bigSeed )
00119         { seed(bigSeed); }
00120 
00121 inline MTRand::MTRand()
00122         { seed(); }
00123 
00124 inline double MTRand::rand()
00125     { return double(randInt()) * 2.3283064370807974e-10; }
00126 
00127 inline double MTRand::rand( const double& n )
00128         { return rand() * n; }
00129 
00130 inline double MTRand::randExc()
00131         { return double(randInt()) * 2.3283064365386963e-10; }
00132 
00133 inline double MTRand::randExc( const double& n )
00134         { return randExc() * n; }
00135 
00136 inline double MTRand::randDblExc()
00137         { return double( 1.0 + randInt() ) * 2.3283064359965952e-10; }
00138 
00139 inline double MTRand::randDblExc( const double& n )
00140         { return randDblExc() * n; }
00141 
00142 inline MTRand::uint32 MTRand::randInt()
00143 {
00144         if( left == 0 ) reload();
00145         --left;
00146                 
00147         register uint32 s1;
00148         s1 = *pNext++;
00149         s1 ^= (s1 >> 11);
00150         s1 ^= (s1 <<  7) & 0x9d2c5680U;
00151         s1 ^= (s1 << 15) & 0xefc60000U;
00152         return ( s1 ^ (s1 >> 18) );
00153 }
00154 
00155 
00156 inline MTRand::uint32 MTRand::randInt( const uint32& n )
00157 {
00158         // Find which bits are used in n
00159         uint32 used = ~0;
00160         for( uint32 m = n; m; used <<= 1, m >>= 1 ) {}
00161         used = ~used;
00162         
00163         // Draw numbers until one is found in [0,n]
00164         uint32 i;
00165         do
00166                 i = randInt() & used;  // toss unused bits to shorten search
00167         while( i > n );
00168         return i;
00169 }
00170 
00171 
00172 inline void MTRand::seed( uint32 oneSeed )
00173 {
00174         // Seed the generator with a simple uint32
00175         register uint32 *s;
00176         register int i;
00177         for( i = N, s = state;
00178              i--;
00179                  *s    = oneSeed & 0xffff0000,
00180                  *s++ |= ( (oneSeed *= 69069U)++ & 0xffff0000 ) >> 16,
00181                  (oneSeed *= 69069U)++ ) {}  // hard to read, but fast
00182         reload();
00183 }
00184 
00185 
00186 inline void MTRand::seed( uint32 *const bigSeed )
00187 {
00188         // Seed the generator with an array of 624 uint32's
00189         // There are 2^19937-1 possible initial states.  This function allows
00190         // any one of those to be chosen by providing 19937 bits.  The lower
00191         // 31 bits of the first element, bigSeed[0], are discarded.  Any bits
00192         // above the lower 32 in each element are also discarded.  Theoretically,
00193         // the rest of the array can contain any values except all zeroes.
00194         // Just call seed() if you want to get array from /dev/urandom
00195         register uint32 *s = state, *b = bigSeed;
00196         register int i = N;
00197         for( ; i--; *s++ = *b++ & 0xffffffff ) {}
00198         reload();
00199 }
00200 
00201 
00202 inline void MTRand::seed()
00203 {
00204         // Seed the generator with an array from /dev/urandom if available
00205         // Otherwise use a hash of time() and clock() values
00206         
00207         // First try getting an array from /dev/urandom
00208         FILE* urandom = fopen( "/dev/urandom", "rb" );
00209         if( urandom )
00210         {
00211                 register uint32 *s = state;
00212                 register int i = N;
00213                 register bool success = true;
00214                 while( success && i-- )
00215                 {
00216                         success = fread( s, sizeof(uint32), 1, urandom );
00217                         *s++ &= 0xffffffff;  // filter in case uint32 > 32 bits
00218                 }
00219                 fclose(urandom);
00220                 if( success )
00221                 {
00222                         // There is a 1 in 2^19937 chance that a working urandom gave
00223                         // 19937 consecutive zeroes and will make the generator fail
00224                         // Ignore that case and continue with initialization
00225                         reload();
00226                         return;
00227                 }
00228         }
00229         
00230         // Was not successful, so use time() and clock() instead
00231         seed( hash( time(NULL), clock() ) );
00232 }
00233 
00234 
00235 inline void MTRand::reload()
00236 {
00237         // Generate N new values in state
00238         // Made clearer and faster by Matthew Bellew (matthew.bellew@home.com)
00239         register uint32 *p = state;
00240         register int i;
00241         for( i = N - M; i--; ++p )
00242                 *p = twist( p[M], p[0], p[1] );
00243         for( i = M; --i; ++p )
00244                 *p = twist( p[M-N], p[0], p[1] );
00245         *p = twist( p[M-N], p[0], state[0] );
00246 
00247         left = N, pNext = state;
00248 }
00249 
00250 
00251 inline MTRand::uint32 MTRand::hash( time_t t, clock_t c )
00252 {
00253         // Get a uint32 from t and c
00254         // Better than uint32(x) in case x is floating point in [0,1]
00255         // Based on code by Lawrence Kirby (fred@genesis.demon.co.uk)
00256 
00257         static uint32 differ = 0;  // guarantee time-based seeds will change
00258 
00259         uint32 h1 = 0;
00260         unsigned char *p = (unsigned char *) &t;
00261         for( size_t i = 0; i < sizeof(t); ++i )
00262         {
00263                 h1 *= UCHAR_MAX + 2U;
00264                 h1 += p[i];
00265         }
00266         uint32 h2 = 0;
00267         p = (unsigned char *) &c;
00268         for( size_t j = 0; j < sizeof(c); ++j )
00269         {
00270                 h2 *= UCHAR_MAX + 2U;
00271                 h2 += p[j];
00272         }
00273         return ( h1 + differ++ ) ^ h2;
00274 }
00275 
00276 
00277 inline void MTRand::save( uint32* saveArray ) const
00278 {
00279         register uint32 *sa = saveArray;
00280         register const uint32 *s = state;
00281         register int i = N;
00282         for( ; i--; *sa++ = *s++ ) {}
00283         *sa = left;
00284 }
00285 
00286 
00287 inline void MTRand::load( uint32 *const loadArray )
00288 {
00289         register uint32 *s = state;
00290         register uint32 *la = loadArray;
00291         register int i = N;
00292         for( ; i--; *s++ = *la++ ) {}
00293         left = *la;
00294         pNext = &state[N-left];
00295 }
00296 
00297 
00298 inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand )
00299 {
00300         register const MTRand::uint32 *s = mtrand.state;
00301         register int i = mtrand.N;
00302         for( ; i--; os << *s++ << "\t" ) {}
00303         return os << mtrand.left;
00304 }
00305 
00306 
00307 inline std::istream& operator>>( std::istream& is, MTRand& mtrand )
00308 {
00309         register MTRand::uint32 *s = mtrand.state;
00310         register int i = mtrand.N;
00311         for( ; i--; is >> *s++ ) {}
00312         is >> mtrand.left;
00313         mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left];
00314         return is;
00315 }
00316 
00317 #endif  //MERSENNETWISTER_H
00318 
00319 // Change log:
00320 //
00321 // v0.1 - First release on 15 May 2000
00322 //      - Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
00323 //      - Translated from C to C++
00324 //      - Made completely ANSI compliant
00325 //      - Designed convenient interface for initialization, seeding, and
00326 //        obtaining numbers in default or user-defined ranges
00327 //      - Added automatic seeding from /dev/urandom or time() and clock()
00328 //      - Provided functions for saving and loading generator state
00329 //
00330 // v0.2 - Fixed bug which reloaded generator one step too late
00331 //
00332 // v0.3 - Switched to clearer, faster reload() code from Matthew Bellew
00333 //
00334 // v0.4 - Removed trailing newline in saved generator format to be consistent
00335 //        with output format of built-in types
00336 //
00337 // v0.5 - Improved portability by replacing static const int's with enum's and
00338 //        clarifying return values in seed(); suggested by Eric Heimburg
00339 //      - Removed MAXINT constant; use 0xffffffff instead
00340 //
00341 // v0.6 - Eliminated seed overflow when uint32 is larger than 32 bits
00342 //      - Changed integer [0,n] generator to give better uniformity
00343 //
00344 // v0.7 - Fixed operator precedence ambiguity in reload()
00345 //      - Added access for real numbers in (0,1) and (0,n)
00346 //
00347 // v0.8 - Included time.h header to properly support time_t and clock_t

Generated on Thu Jun 16 17:13:47 2005 for Matvec by doxygen1.2.16