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 13 *******************************************************************************/ 14 15 module tango.math.random.Twister; 16 17 18 version (Win32) 19 private extern(Windows) int QueryPerformanceCounter (ulong *); 20 21 version (Posix) 22 { 23 private import tango.stdc.posix.sys.time; 24 } 25 26 /******************************************************************************* 27 28 Wrapper for the Mersenne twister. 29 30 The Mersenne twister is a pseudorandom number generator linked to 31 CR developed in 1997 by Makoto Matsumoto and Takuji Nishimura that 32 is based on a matrix linear recurrence over a finite binary field 33 F2. It provides for fast generation of very high quality pseudorandom 34 numbers, having been designed specifically to rectify many of the 35 flaws found in older algorithms. 36 37 Mersenne Twister has the following desirable properties: 38 --- 39 1. It was designed to have a period of 2^19937 - 1 (the creators 40 of the algorithm proved this property). 41 42 2. It has a very high order of dimensional equidistribution. 43 This implies that there is negligible serial correlation between 44 successive values in the output sequence. 45 46 3. It passes numerous tests for statistical randomness, including 47 the stringent Diehard tests. 48 49 4. It is fast. 50 --- 51 52 *******************************************************************************/ 53 54 struct Twister 55 { 56 public alias natural toInt; 57 public alias fraction toReal; 58 59 private enum : uint // Period parameters 60 { 61 N = 624, 62 M = 397, 63 MATRIX_A = 0x9908b0df, // constant vector a 64 UPPER_MASK = 0x80000000, // most significant w-r bits 65 LOWER_MASK = 0x7fffffff, // least significant r bits 66 } 67 68 private uint[N] mt; // the array for the state vector 69 private uint mti=mt.length+1; // mti==mt.length+1 means mt[] is not initialized 70 private uint vLastRand; // The most recent random uint returned. 71 72 /********************************************************************** 73 74 A global, shared instance, seeded via startup time 75 76 **********************************************************************/ 77 78 public static __gshared Twister instance; 79 80 shared static this () 81 { 82 instance.seed(); 83 } 84 85 /********************************************************************** 86 87 Creates and seeds a new generator with the current time 88 89 **********************************************************************/ 90 91 static Twister opCall () 92 { 93 Twister rand; 94 rand.seed(); 95 return rand; 96 } 97 98 /********************************************************************** 99 100 Returns X such that 0 <= X < max 101 102 **********************************************************************/ 103 104 uint natural (uint max) 105 { 106 return natural() % max; 107 } 108 109 /********************************************************************** 110 111 Returns X such that min <= X < max 112 113 **********************************************************************/ 114 115 uint natural (uint min, uint max) 116 { 117 return (natural() % (max-min)) + min; 118 } 119 120 /********************************************************************** 121 122 Returns X such that 0 <= X <= uint.max 123 124 **********************************************************************/ 125 126 uint natural (bool pAddEntropy = false) 127 { 128 uint y; 129 static uint mag01[2] =[0, MATRIX_A]; 130 131 if (mti >= mt.length) { 132 int kk; 133 134 if (pAddEntropy || mti > mt.length) 135 { 136 seed (5489U, pAddEntropy); 137 } 138 139 for (kk=0;kk<mt.length-M;kk++) 140 { 141 y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); 142 mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 1U]; 143 } 144 for (;kk<mt.length-1;kk++) { 145 y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); 146 mt[kk] = mt[kk+(M-mt.length)] ^ (y >> 1) ^ mag01[y & 1U]; 147 } 148 y = (mt[mt.length-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); 149 mt[mt.length-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 1U]; 150 151 mti = 0; 152 } 153 154 y = mt[mti++]; 155 156 y ^= (y >> 11); 157 y ^= (y << 7) & 0x9d2c5680U; 158 y ^= (y << 15) & 0xefc60000U; 159 y ^= (y >> 18); 160 161 vLastRand = y; 162 return y; 163 } 164 165 /********************************************************************** 166 167 generates a random number on [0,1] interval 168 169 **********************************************************************/ 170 171 double inclusive () 172 { 173 return natural()*(1.0/cast(double)uint.max); 174 } 175 176 /********************************************************************** 177 178 generates a random number on (0,1) interval 179 180 **********************************************************************/ 181 182 double exclusive () 183 { 184 return ((cast(double)natural()) + 0.5)*(1.0/(cast(double)uint.max+1.0)); 185 } 186 187 /********************************************************************** 188 189 generates a random number on [0,1) interval 190 191 **********************************************************************/ 192 193 double fraction () 194 { 195 return natural()*(1.0/(cast(double)uint.max+1.0)); 196 } 197 198 /********************************************************************** 199 200 generates a random number on [0,1) with 53-bit resolution 201 202 **********************************************************************/ 203 204 double fractionEx () 205 { 206 uint a = natural() >> 5, b = natural() >> 6; 207 return(a * 67108864.0 + b) * (1.0 / 9007199254740992.0); 208 } 209 210 /********************************************************************** 211 212 Seed the generator with current time 213 214 **********************************************************************/ 215 216 void seed () 217 { 218 ulong s; 219 220 version (Posix) 221 { 222 timeval tv; 223 224 gettimeofday (&tv, null); 225 s = tv.tv_usec; 226 } 227 version (Win32) 228 QueryPerformanceCounter (&s); 229 230 return seed (cast(uint) s); 231 } 232 233 /********************************************************************** 234 235 initializes the generator with a seed 236 237 **********************************************************************/ 238 239 void seed (uint s, bool pAddEntropy = false) 240 { 241 mt[0]= (s + (pAddEntropy ? vLastRand + cast(uint) &this : 0)) & 0xffffffffU; 242 for (mti=1; mti<mt.length; mti++){ 243 mt[mti] = (1812433253U * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); 244 mt[mti] &= 0xffffffffU; 245 } 246 } 247 248 /********************************************************************** 249 250 initialize by an array with array-length init_key is 251 the array for initializing keys 252 253 **********************************************************************/ 254 255 void init (const(uint[]) init_key, bool pAddEntropy = false) 256 { 257 size_t k; 258 int i, j; 259 i=1; 260 j=0; 261 262 seed (19650218U, pAddEntropy); 263 for (k = (mt.length > init_key.length ? mt.length : init_key.length); k; k--) { 264 mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525U))+ init_key[j] + j; 265 mt[i] &= 0xffffffffU; 266 i++; 267 j++; 268 269 if (i >= mt.length){ 270 mt[0] = mt[mt.length-1]; 271 i=1; 272 } 273 274 if (j >= init_key.length){ 275 j=0; 276 } 277 } 278 279 for (k=mt.length-1; k; k--) { 280 mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941U))- i; 281 mt[i] &= 0xffffffffU; 282 i++; 283 284 if (i>=mt.length){ 285 mt[0] = mt[mt.length-1]; 286 i=1; 287 } 288 } 289 mt[0] |= 0x80000000U; 290 mti=0; 291 } 292 } 293 294 295 /****************************************************************************** 296 297 298 ******************************************************************************/ 299 300 debug (Twister) 301 { 302 import tango.io.Stdout; 303 import tango.time.StopWatch; 304 305 void main() 306 { 307 auto dbl = Twister(); 308 auto count = 100_000_000; 309 StopWatch w; 310 311 w.start; 312 double v1; 313 for (int i=count; --i;) 314 v1 = dbl.fraction; 315 Stdout.formatln ("{} fraction, {}/s, {:f10}", count, count/w.stop, v1); 316 317 w.start; 318 for (int i=count; --i;) 319 v1 = dbl.fractionEx; 320 Stdout.formatln ("{} fractionEx, {}/s, {:f10}", count, count/w.stop, v1); 321 322 for (int i=count; --i;) 323 { 324 auto v = dbl.fraction; 325 if (v <= 0.0 || v >= 1.0) 326 { 327 Stdout.formatln ("fraction {:f10}", v); 328 break; 329 } 330 v = dbl.fractionEx; 331 if (v <= 0.0 || v >= 1.0) 332 { 333 Stdout.formatln ("fractionEx {:f10}", v); 334 break; 335 } 336 } 337 } 338 }