Advertisement
r4m0n

Enhanced Mersenne Twister C++

Sep 20th, 2019
183
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 17.31 KB | None | 0 0
  1. // MersenneTwister.h
  2. // Mersenne Twister random number generator -- a C++ class MTRand
  3. // Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
  4. // Richard J. Wagner  v1.1  28 September 2009  wagnerr@umich.edu
  5.  
  6. // The Mersenne Twister is an algorithm for generating random numbers.  It
  7. // was designed with consideration of the flaws in various other generators.
  8. // The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
  9. // are far greater.  The generator is also fast; it avoids multiplication and
  10. // division, and it benefits from caches and pipelines.  For more information
  11. // see the inventors' web page at
  12. // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
  13.  
  14. // Reference
  15. // M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally
  16. // Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on
  17. // Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30.
  18.  
  19. // Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
  20. // Copyright (C) 2000 - 2009, Richard J. Wagner
  21. // All rights reserved.
  22. //
  23. // Redistribution and use in source and binary forms, with or without
  24. // modification, are permitted provided that the following conditions
  25. // are met:
  26. //
  27. //   1. Redistributions of source code must retain the above copyright
  28. //      notice, this list of conditions and the following disclaimer.
  29. //
  30. //   2. Redistributions in binary form must reproduce the above copyright
  31. //      notice, this list of conditions and the following disclaimer in the
  32. //      documentation and/or other materials provided with the distribution.
  33. //
  34. //   3. The names of its contributors may not be used to endorse or promote
  35. //      products derived from this software without specific prior written
  36. //      permission.
  37. //
  38. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  39. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  40. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  41. // ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  42. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  43. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  44. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  45. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  46. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  47. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  48. // POSSIBILITY OF SUCH DAMAGE.
  49.  
  50. // The original code included the following notice:
  51. //
  52. //     When you use this, send an email to: m-mat@math.sci.hiroshima-u.ac.jp
  53. //     with an appropriate reference to your work.
  54. //
  55. // It would be nice to CC: wagnerr@umich.edu and Cokus@math.washington.edu
  56. // when you write.
  57.  
  58. #ifndef MERSENNETWISTER_H
  59. #define MERSENNETWISTER_H
  60.  
  61. // Not thread safe (unless auto-initialization is avoided and each thread has
  62. // its own MTRand object)
  63.  
  64. #include <iostream>
  65. #include <climits>
  66. #include <cstdio>
  67. #include <ctime>
  68. #include <cmath>
  69.  
  70. class MTRand {
  71. // Data
  72. public:
  73.     typedef unsigned long uint32;  // unsigned integer type, at least 32 bits
  74.  
  75.     enum { N = 624 };       // length of state vector
  76.     enum { SAVE = N + 1 };  // length of array for save()
  77.  
  78. protected:
  79.     enum { M = 397 };  // period parameter
  80.  
  81.     uint32 state[N];   // internal state
  82.     uint32 *pNext;     // next value to get from state
  83.     int left;          // number of values left before reload needed
  84.  
  85. // Methods
  86. public:
  87.     MTRand( const uint32 oneSeed );  // initialize with a simple uint32
  88.     MTRand( uint32 *const bigSeed, uint32 const seedLength = N );  // or array
  89.     MTRand();  // auto-initialize with /dev/urandom or time() and clock()
  90.     MTRand( const MTRand& o );  // copy
  91.  
  92.     // Do NOT use for CRYPTOGRAPHY without securely hashing several returned
  93.     // values together, otherwise the generator state can be learned after
  94.     // reading 624 consecutive values.
  95.  
  96.     // Access to 32-bit random numbers
  97.     uint32 randInt();                     // integer in [0,2^32-1]
  98.     uint32 randInt( const uint32 n );     // integer in [0,n] for n < 2^32
  99.     double rand();                        // real number in [0,1]
  100.     double rand( const double n );        // real number in [0,n]
  101.     double randExc();                     // real number in [0,1)
  102.     double randExc( const double n );     // real number in [0,n)
  103.     double randDblExc();                  // real number in (0,1)
  104.     double randDblExc( const double n );  // real number in (0,n)
  105.     double operator()();                  // same as rand()
  106.  
  107.     // Access to 53-bit random numbers (capacity of IEEE double precision)
  108.     double rand53();  // real number in [0,1)
  109.  
  110.     // Access to nonuniform random number distributions
  111.     double randNorm( const double mean = 0.0, const double stddev = 1.0 );
  112.     double randGamma( const double a = 1.0, const double b = 1.0 );
  113.     double randBeta( const double a = 1.0, const double b = 1.0 );
  114.  
  115.     // Re-seeding functions with same behavior as initializers
  116.     void seed( const uint32 oneSeed );
  117.     void seed( uint32 *const bigSeed, const uint32 seedLength = N );
  118.     void seed();
  119.  
  120.     // Saving and loading generator state
  121.     void save( uint32* saveArray ) const;  // to array of size SAVE
  122.     void load( uint32 *const loadArray );  // from such array
  123.     friend std::ostream& operator<<( std::ostream& os, const MTRand& mtrand );
  124.     friend std::istream& operator>>( std::istream& is, MTRand& mtrand );
  125.     MTRand& operator=( const MTRand& o );
  126.  
  127. protected:
  128.     void initialize( const uint32 oneSeed );
  129.     void reload();
  130.     uint32 hiBit( const uint32 u ) const {
  131.         return u & 0x80000000UL;
  132.     }
  133.     uint32 loBit( const uint32 u ) const {
  134.         return u & 0x00000001UL;
  135.     }
  136.     uint32 loBits( const uint32 u ) const {
  137.         return u & 0x7fffffffUL;
  138.     }
  139.     uint32 mixBits( const uint32 u, const uint32 v ) const {
  140.         return hiBit(u) | loBits(v);
  141.     }
  142.     uint32 magic( const uint32 u ) const {
  143.         return loBit(u) ? 0x9908b0dfUL : 0x0UL;
  144.     }
  145.     uint32 twist( const uint32 m, const uint32 s0, const uint32 s1 ) const {
  146.         return m ^ (mixBits(s0,s1)>>1) ^ magic(s1);
  147.     }
  148.     static uint32 hash( time_t t, clock_t c );
  149. };
  150.  
  151. // Functions are defined in order of usage to assist inlining
  152.  
  153. inline MTRand::uint32 MTRand::hash( time_t t, clock_t c ) {
  154.     // Get a uint32 from t and c
  155.     // Better than uint32(x) in case x is floating point in [0,1]
  156.     // Based on code by Lawrence Kirby (fred@genesis.demon.co.uk)
  157.  
  158.     static uint32 differ = 0;  // guarantee time-based seeds will change
  159.  
  160.     uint32 h1 = 0;
  161.     unsigned char *p = (unsigned char *) &t;
  162.     for ( size_t i = 0; i < sizeof(t); ++i ) {
  163.         h1 *= UCHAR_MAX + 2U;
  164.         h1 += p[i];
  165.     }
  166.     uint32 h2 = 0;
  167.     p = (unsigned char *) &c;
  168.     for ( size_t j = 0; j < sizeof(c); ++j ) {
  169.         h2 *= UCHAR_MAX + 2U;
  170.         h2 += p[j];
  171.     }
  172.     return ( h1 + differ++ ) ^ h2;
  173. }
  174.  
  175. inline void MTRand::initialize( const uint32 seed ) {
  176.     // Initialize generator state with seed
  177.     // See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
  178.     // In previous versions, most significant bits (MSBs) of the seed affect
  179.     // only MSBs of the state array.  Modified 9 Jan 2002 by Makoto Matsumoto.
  180.     register uint32 *s = state;
  181.     register uint32 *r = state;
  182.     register int i = 1;
  183.     *s++ = seed & 0xffffffffUL;
  184.     for ( ; i < N; ++i ) {
  185.         *s++ = ( 1812433253UL * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffUL;
  186.         r++;
  187.     }
  188. }
  189.  
  190. inline void MTRand::reload() {
  191.     // Generate N new values in state
  192.     // Made clearer and faster by Matthew Bellew (matthew.bellew@home.com)
  193.     static const int MmN = int(M) - int(N);  // in case enums are unsigned
  194.     register uint32 *p = state;
  195.     register int i;
  196.     for ( i = N - M; i--; ++p )
  197.         *p = twist( p[M], p[0], p[1] );
  198.     for ( i = M; --i; ++p )
  199.         *p = twist( p[MmN], p[0], p[1] );
  200.     *p = twist( p[MmN], p[0], state[0] );
  201.  
  202.     left = N, pNext = state;
  203. }
  204.  
  205. inline void MTRand::seed( const uint32 oneSeed ) {
  206.     // Seed the generator with a simple uint32
  207.     initialize(oneSeed);
  208.     reload();
  209. }
  210.  
  211. inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength ) {
  212.     // Seed the generator with an array of uint32's
  213.     // There are 2^19937-1 possible initial states.  This function allows
  214.     // all of those to be accessed by providing at least 19937 bits (with a
  215.     // default seed length of N = 624 uint32's).  Any bits above the lower 32
  216.     // in each element are discarded.
  217.     // Just call seed() if you want to get array from /dev/urandom
  218.     initialize(19650218UL);
  219.     register int i = 1;
  220.     register uint32 j = 0;
  221.     register int k = ( N > seedLength ? N : seedLength );
  222.     for ( ; k; --k ) {
  223.         state[i] =
  224.             state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1664525UL );
  225.         state[i] += ( bigSeed[j] & 0xffffffffUL ) + j;
  226.         state[i] &= 0xffffffffUL;
  227.         ++i;
  228.         ++j;
  229.         if ( i >= N ) {
  230.             state[0] = state[N-1];
  231.             i = 1;
  232.         }
  233.         if ( j >= seedLength ) j = 0;
  234.     }
  235.     for ( k = N - 1; k; --k ) {
  236.         state[i] =
  237.             state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL );
  238.         state[i] -= i;
  239.         state[i] &= 0xffffffffUL;
  240.         ++i;
  241.         if ( i >= N ) {
  242.             state[0] = state[N-1];
  243.             i = 1;
  244.         }
  245.     }
  246.     state[0] = 0x80000000UL;  // MSB is 1, assuring non-zero initial array
  247.     reload();
  248. }
  249.  
  250. inline void MTRand::seed() {
  251.     // Seed the generator with an array from /dev/urandom if available
  252.     // Otherwise use a hash of time() and clock() values
  253.  
  254.     // First try getting an array from /dev/urandom
  255.     FILE* urandom = fopen( "/dev/urandom", "rb" );
  256.     if ( urandom ) {
  257.         uint32 bigSeed[N];
  258.         register uint32 *s = bigSeed;
  259.         register int i = N;
  260.         register bool success = true;
  261.         while ( success && i-- )
  262.             success = fread( s++, sizeof(uint32), 1, urandom );
  263.         fclose(urandom);
  264.         if ( success ) {
  265.             seed( bigSeed, N );
  266.             return;
  267.         }
  268.     }
  269.  
  270.     // Was not successful, so use time() and clock() instead
  271.     seed( hash( time(NULL), clock() ) );
  272. }
  273.  
  274. inline MTRand::MTRand( const uint32 oneSeed ) {
  275.     seed(oneSeed);
  276. }
  277.  
  278. inline MTRand::MTRand( uint32 *const bigSeed, const uint32 seedLength ) {
  279.     seed(bigSeed,seedLength);
  280. }
  281.  
  282. inline MTRand::MTRand() {
  283.     seed();
  284. }
  285.  
  286. inline MTRand::MTRand( const MTRand& o ) {
  287.     register const uint32 *t = o.state;
  288.     register uint32 *s = state;
  289.     register int i = N;
  290.     for ( ; i--; *s++ = *t++ ) {}
  291.     left = o.left;
  292.     pNext = &state[N-left];
  293. }
  294.  
  295. inline MTRand::uint32 MTRand::randInt() {
  296.     // Pull a 32-bit integer from the generator state
  297.     // Every other access function simply transforms the numbers extracted here
  298.  
  299.     if ( left == 0 ) reload();
  300.     --left;
  301.  
  302.     register uint32 s1;
  303.     s1 = *pNext++;
  304.     s1 ^= (s1 >> 11);
  305.     s1 ^= (s1 <<  7) & 0x9d2c5680UL;
  306.     s1 ^= (s1 << 15) & 0xefc60000UL;
  307.     return ( s1 ^ (s1 >> 18) );
  308. }
  309.  
  310. inline MTRand::uint32 MTRand::randInt( const uint32 n ) {
  311.     // Find which bits are used in n
  312.     // Optimized by Magnus Jonsson (magnus@smartelectronix.com)
  313.     uint32 used = n;
  314.     used |= used >> 1;
  315.     used |= used >> 2;
  316.     used |= used >> 4;
  317.     used |= used >> 8;
  318.     used |= used >> 16;
  319.  
  320.     // Draw numbers until one is found in [0,n]
  321.     uint32 i;
  322.     do
  323.         i = randInt() & used;  // toss unused bits to shorten search
  324.     while ( i > n );
  325.     return i;
  326. }
  327.  
  328. inline double MTRand::rand() {
  329.     return double(randInt()) * (1.0/4294967295.0);
  330. }
  331.  
  332. inline double MTRand::rand( const double n ) {
  333.     return rand() * n;
  334. }
  335.  
  336. inline double MTRand::randExc() {
  337.     return double(randInt()) * (1.0/4294967296.0);
  338. }
  339.  
  340. inline double MTRand::randExc( const double n ) {
  341.     return randExc() * n;
  342. }
  343.  
  344. inline double MTRand::randDblExc() {
  345.     return ( double(randInt()) + 0.5 ) * (1.0/4294967296.0);
  346. }
  347.  
  348. inline double MTRand::randDblExc( const double n ) {
  349.     return randDblExc() * n;
  350. }
  351.  
  352. inline double MTRand::rand53() {
  353.     uint32 a = randInt() >> 5, b = randInt() >> 6;
  354.     return ( a * 67108864.0 + b ) * (1.0/9007199254740992.0);  // by Isaku Wada
  355. }
  356.  
  357. inline double MTRand::randNorm( const double mean, const double stddev ) {
  358.     // Return a real number from a normal (Gaussian) distribution with given
  359.     // mean and standard deviation by polar form of Box-Muller transformation
  360.     double x, y, r;
  361.     do {
  362.         x = 2.0 * rand() - 1.0;
  363.         y = 2.0 * rand() - 1.0;
  364.         r = x * x + y * y;
  365.     } while ( r >= 1.0 || r == 0.0 );
  366.     double s = sqrt( -2.0 * log(r) / r );
  367.     return mean + x * s * stddev;
  368. }
  369.  
  370. inline double MTRand::randGamma( const double a, const double b ) {
  371.     if (a < 1) {
  372.         return randGamma(1.0+a, b)*pow(randDblExc(), 1.0/a);
  373.     }
  374.  
  375.     double x, v, u;
  376.     double d = a-1.0/3.0;
  377.     double c = (1.0/3.0)/sqrt(d);
  378.  
  379.     for (;;) {
  380.         do {
  381.             x = randNorm();
  382.             v = 1.0+c*x;
  383.         } while (v <= 0);
  384.         v = v*v*v;
  385.         u = randDblExc();
  386.  
  387.         if (u < 1-0.0331*x*x*x*x) {
  388.             break;
  389.         }
  390.         if (log(u) < 0.5*x*x + d*(1-v+log(v))) {
  391.             break;
  392.         }
  393.     }
  394.  
  395.     return b*d*v;
  396. }
  397.  
  398. inline double MTRand::randBeta( const double a, const double b ) {
  399.     double x1 = randGamma(a);
  400.     double x2 = randGamma(b);
  401.     return x1/(x1+x2);
  402. }
  403.  
  404. inline double MTRand::operator()() {
  405.     return rand();
  406. }
  407.  
  408. inline void MTRand::save( uint32* saveArray ) const {
  409.     register const uint32 *s = state;
  410.     register uint32 *sa = saveArray;
  411.     register int i = N;
  412.     for ( ; i--; *sa++ = *s++ ) {}
  413.     *sa = left;
  414. }
  415.  
  416. inline void MTRand::load( uint32 *const loadArray ) {
  417.     register uint32 *s = state;
  418.     register uint32 *la = loadArray;
  419.     register int i = N;
  420.     for ( ; i--; *s++ = *la++ ) {}
  421.     left = *la;
  422.     pNext = &state[N-left];
  423. }
  424.  
  425. inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand ) {
  426.     register const MTRand::uint32 *s = mtrand.state;
  427.     register int i = mtrand.N;
  428.     for ( ; i--; os << *s++ << "\t" ) {}
  429.     return os << mtrand.left;
  430. }
  431.  
  432. inline std::istream& operator>>( std::istream& is, MTRand& mtrand ) {
  433.     register MTRand::uint32 *s = mtrand.state;
  434.     register int i = mtrand.N;
  435.     for ( ; i--; is >> *s++ ) {}
  436.     is >> mtrand.left;
  437.     mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left];
  438.     return is;
  439. }
  440.  
  441. inline MTRand& MTRand::operator=( const MTRand& o ) {
  442.     if ( this == &o ) return (*this);
  443.     register const uint32 *t = o.state;
  444.     register uint32 *s = state;
  445.     register int i = N;
  446.     for ( ; i--; *s++ = *t++ ) {}
  447.     left = o.left;
  448.     pNext = &state[N-left];
  449.     return (*this);
  450. }
  451.  
  452. #endif  // MERSENNETWISTER_H
  453.  
  454. // Change log:
  455. //
  456. // v0.1 - First release on 15 May 2000
  457. //      - Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
  458. //      - Translated from C to C++
  459. //      - Made completely ANSI compliant
  460. //      - Designed convenient interface for initialization, seeding, and
  461. //        obtaining numbers in default or user-defined ranges
  462. //      - Added automatic seeding from /dev/urandom or time() and clock()
  463. //      - Provided functions for saving and loading generator state
  464. //
  465. // v0.2 - Fixed bug which reloaded generator one step too late
  466. //
  467. // v0.3 - Switched to clearer, faster reload() code from Matthew Bellew
  468. //
  469. // v0.4 - Removed trailing newline in saved generator format to be consistent
  470. //        with output format of built-in types
  471. //
  472. // v0.5 - Improved portability by replacing static const int's with enum's and
  473. //        clarifying return values in seed(); suggested by Eric Heimburg
  474. //      - Removed MAXINT constant; use 0xffffffffUL instead
  475. //
  476. // v0.6 - Eliminated seed overflow when uint32 is larger than 32 bits
  477. //      - Changed integer [0,n] generator to give better uniformity
  478. //
  479. // v0.7 - Fixed operator precedence ambiguity in reload()
  480. //      - Added access for real numbers in (0,1) and (0,n)
  481. //
  482. // v0.8 - Included time.h header to properly support time_t and clock_t
  483. //
  484. // v1.0 - Revised seeding to match 26 Jan 2002 update of Nishimura and Matsumoto
  485. //      - Allowed for seeding with arrays of any length
  486. //      - Added access for real numbers in [0,1) with 53-bit resolution
  487. //      - Added access for real numbers from normal (Gaussian) distributions
  488. //      - Increased overall speed by optimizing twist()
  489. //      - Doubled speed of integer [0,n] generation
  490. //      - Fixed out-of-range number generation on 64-bit machines
  491. //      - Improved portability by substituting literal constants for long enum's
  492. //      - Changed license from GNU LGPL to BSD
  493. //
  494. // v1.1 - Corrected parameter label in randNorm from "variance" to "stddev"
  495. //      - Changed randNorm algorithm from basic to polar form for efficiency
  496. //      - Updated includes from deprecated <xxxx.h> to standard <cxxxx> forms
  497. //      - Cleaned declarations and definitions to please Intel compiler
  498. //      - Revised twist() operator to work on ones'-complement machines
  499. //      - Fixed reload() function to work when N and M are unsigned
  500. //      - Added copy constructor and copy operator from Salvador Espana
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement