1 /******************************************************************************* 2 3 copyright: Copyright (C) 1997--2004, Makoto Matsumoto, 4 Takuji Nishimura, and Eric Landry; All rights reserved 5 6 7 license: BSD style: $(LICENSE) 8 9 version: Jan 2008: Initial release 10 11 author: KeYeR (D interface) keyer@team0xf.com 12 fawzi (converted to engine) 13 14 *******************************************************************************/ 15 16 module tango.math.random.engines.Twister; 17 private import Integer = tango.text.convert.Integer; 18 19 /******************************************************************************* 20 21 Wrapper for the Mersenne twister. 22 23 The Mersenne twister is a pseudorandom number generator linked to 24 CR developed in 1997 by Makoto Matsumoto and Takuji Nishimura that 25 is based on a matrix linear recurrence over a finite binary field 26 F2. It provides for fast generation of very high quality pseudorandom 27 numbers, having been designed specifically to rectify many of the 28 flaws found in older algorithms. 29 30 Mersenne Twister has the following desirable properties: 31 --- 32 1. It was designed to have a period of 2^19937 - 1 (the creators 33 of the algorithm proved this property). 34 35 2. It has a very high order of dimensional equidistribution. 36 This implies that there is negligible serial correlation between 37 successive values in the output sequence. 38 39 3. It passes numerous tests for statistical randomness, including 40 the stringent Diehard tests. 41 42 4. It is fast. 43 --- 44 45 *******************************************************************************/ 46 47 struct Twister 48 { 49 private enum : uint { 50 // Period parameters 51 N = 624, 52 M = 397, 53 MATRIX_A = 0x9908b0df, // constant vector a 54 UPPER_MASK = 0x80000000, // most significant w-r bits 55 LOWER_MASK = 0x7fffffff, // least significant r bits 56 } 57 enum int canCheckpoint=true; 58 enum int canSeed=true; 59 60 private uint[N] mt; // the array for the state vector 61 private uint mti=mt.length+1; // mti==mt.length+1 means mt[] is not initialized 62 63 /// returns a random uint 64 uint next () 65 { 66 uint y; 67 static uint[2] mag01 =[0, MATRIX_A]; 68 69 if (mti >= mt.length) { 70 int kk; 71 72 for (kk=0;kk<mt.length-M;kk++) 73 { 74 y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); 75 mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 1U]; 76 } 77 for (;kk<mt.length-1;kk++) { 78 y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); 79 mt[kk] = mt[kk+(M-mt.length)] ^ (y >> 1) ^ mag01[y & 1U]; 80 } 81 y = (mt[mt.length-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); 82 mt[mt.length-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 1U]; 83 84 mti = 0; 85 } 86 87 y = mt[mti++]; 88 89 y ^= (y >> 11); 90 y ^= (y << 7) & 0x9d2c5680UL; 91 y ^= (y << 15) & 0xefc60000UL; 92 y ^= (y >> 18); 93 94 return y; 95 } 96 /// returns a random byte 97 ubyte nextB(){ 98 return cast(ubyte)(next() & 0xFF); 99 } 100 /// returns a random long 101 ulong nextL(){ 102 return ((cast(ulong)next())<<32)+cast(ulong)next(); 103 } 104 105 /// initializes the generator with a uint as seed 106 void seed (uint s) 107 { 108 mt[0]= s & 0xffff_ffffU; // this is very suspicious, was the previous line incorrectly translated from C??? 109 for (mti=1; mti<mt.length; mti++){ 110 mt[mti] = cast(uint)(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); 111 mt[mti] &= 0xffff_ffffUL; // this is very suspicious, was the previous line incorrectly translated from C??? 112 } 113 } 114 /// adds entropy to the generator 115 void addEntropy(scope uint delegate() r){ 116 int i, j, k; 117 i=1; 118 j=0; 119 120 for (k = mt.length; k; k--) { 121 mt[i] = cast(uint)((mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))+ r() + j); 122 mt[i] &= 0xffff_ffffUL; // this is very suspicious, was the previous line incorrectly translated from C??? 123 i++; 124 j++; 125 126 if (i >= mt.length){ 127 mt[0] = mt[mt.length-1]; 128 i=1; 129 } 130 } 131 132 for (k=mt.length-1; k; k--) { 133 mt[i] = cast(uint)((mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))- i); 134 mt[i] &= 0xffffffffUL; // this is very suspicious, was the previous line incorrectly translated from C??? 135 i++; 136 137 if (i>=mt.length){ 138 mt[0] = mt[mt.length-1]; 139 i=1; 140 } 141 } 142 mt[0] |= 0x80000000UL; 143 mti=0; 144 } 145 /// seeds the generator 146 void seed(scope uint delegate() r){ 147 seed (19650218UL); 148 addEntropy(r); 149 } 150 /// writes the current status in a string 151 immutable(char)[] toString(){ 152 char[] res=new char[7+(N+1)*9]; 153 int i=0; 154 res[i..i+7]="Twister"[]; 155 i+=7; 156 res[i]='_'; 157 ++i; 158 Integer.format(res[i..i+8],mti,cast(char[])"x8"); 159 i+=8; 160 foreach (val;mt){ 161 res[i]='_'; 162 ++i; 163 Integer.format(res[i..i+8],val,cast(char[])"x8"); 164 i+=8; 165 } 166 assert(i==res.length,"unexpected size"); 167 return cast(immutable(char)[])res; 168 } 169 /// reads the current status from a string (that should have been trimmed) 170 /// returns the number of chars read 171 size_t fromString(const(char[]) s){ 172 size_t i; 173 assert(s[0..7]=="Twister","unexpected kind, expected Twister"); 174 i+=7; 175 assert(s[i]=='_',"no separator _ found"); 176 ++i; 177 size_t ate; 178 mti=cast(uint)Integer.convert(s[i..i+8],16,&ate); 179 assert(ate==8,"unexpected read size"); 180 i+=8; 181 foreach (ref val;mt){ 182 assert(s[i]=='_',"no separator _ found"); 183 ++i; 184 val=cast(uint)Integer.convert(s[i..i+8],16,&ate); 185 assert(ate==8,"unexpected read size"); 186 i+=8; 187 } 188 return i; 189 } 190 191 } 192