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