1 /******************************************************************************* 2 Random number generators 3 4 This is an attempt at having a good flexible and easy to use random number 5 generator. 6 ease of use: 7 $(UL 8 $(LI shared generator for quick usage available through the "rand" object 9 --- 10 int i=rand.uniformR(10); // a random number from [0;10) 11 --- 12 ) 13 $(LI simple Random (non threadsafe) and RandomSync (threadsafe) types to 14 create new generators (for heavy use a good idea is one Random object per thread) 15 ) 16 $(LI several distributions can be requested like this 17 --- 18 rand.distributionD!(type)(paramForDistribution) 19 --- 20 the type can often be avoided if the parameters make it clear. 21 From it single numbers can be generated with .getRandom(), and variables 22 initialized either with call style (var) or with .randomize(var). 23 Utility functions to generate numbers directly are also available. 24 The choice to put all the distribution in a single object that caches them 25 has made (for example) the gamma distribution very easy to implement. 26 ) 27 $(LI sample usage: 28 --- 29 auto r=new Random(); 30 int i; float f; real rv; real[100] ar0; real[] ar=ar0[]; 31 // initialize with uniform distribution 32 i=r.uniform!(int); 33 f=r.uniform!(float); 34 rv=r.uniform!(real); 35 foreach (ref el;ar) 36 el=r.uniform!(real); 37 // another way to do all the previous in one go: 38 r(i)(f)(rv)(ar); 39 // unfortunetely one cannot use directly ar0... 40 // uniform distribution 0..10 41 i=r.uniformR(10); 42 f=r.uniformR(10.0f); 43 rv=r.uniformR(10.0L); 44 foreach (ref el;ar) 45 el=r.uniformR(10.0L); 46 // another way to do all the previous in one go: 47 r.uniformRD(10)(i)(f)(r)(ar); 48 // uniform numbers in [5;10) 49 i=r.uniformR2(5,10); 50 // uniform numbers in (5;10) 51 f=r.uniformR2(5.0f,10.0f); 52 rv=r.uniformR2(5.0L,10.0L); 53 foreach (ref el;ar) 54 el=r.uniformR2(5.0L,10.0L); 55 // another way to do all the previous in one go: 56 r.uniformR2D(5.0L,10.0L)(i)(f)(r)(ar); 57 // uniform distribution -10..10 58 i=r.uniformRSymm(10); 59 // well you get it... 60 r.uniformRSymmD(10)(i)(f)(r)(ar); 61 // any distribution can be stored 62 auto r2=r.uniformRSymmD(10); 63 // and used later 64 r2(ar); 65 // complex distributions (normal,exp,gamma) are produced for the requested type 66 r.normalSource!(float)()(f); 67 // with sigma=2 68 r.normalD(2.0f)(f); 69 // and can be used also to initialize other types 70 r.normalSource!(float)()(r)(ar); 71 r.normalD(2.0f)(r)(ar); 72 // but this is different from 73 r.normalSource!(real)()(i)(r)(ar); 74 r.normalD(2.0L)(i)(r)(ar); 75 // as the source generates numbers of its type that then are simply cast to 76 // the type needed. 77 // Uniform distribution (as its creation for different types has no overhead) 78 // is never cast, so that (for example) bounds exclusion for floats is really 79 // guaranteed. 80 // For the other distribution using a distribution of different type than 81 // the variable should be done with care, as underflow/overflow might ensue. 82 // 83 // Some utility functions are also available 84 int i2=r.uniform!(int)(); 85 int i2=r.randomize(i); // both i and i2 are initialized to the same value 86 float f2=r.normalSigma(3.0f); 87 --- 88 ) 89 ) 90 flexibility: 91 $(UL 92 $(LI easily swappable basic source 93 --- 94 // a random generator that uses the system provided random generator: 95 auto r=RandomG!(Urandom)(); 96 --- 97 One could also build an engine that can be changed at runtime (that calls 98 a delegate for example), but this adds a little overhead, and changing 99 engine is not something done often, so this is not part of the library. 100 ) 101 $(LI ziggurat generator can be easily adapted to any decreasing derivable 102 distribution, the hard parametrization (to find xLast) can be done 103 automatically 104 ) 105 $(LI several distributions available "out of the box" 106 ) 107 ) 108 Quality: 109 $(UL 110 $(LI the default Source combines two surces that pass all statistical tests 111 (KISS+CMWC) 112 (P. L'Ecuyer and R. Simard, ACM Transactions on Mathematical Software (2007), 113 33, 4, Article 22, for KISS, see CMWC engine for the other) 114 ) 115 $(LI floating point uniform generator always initializes the full mantissa, the 116 only flaw is a (*very* small) predilection of 0 as least important bit 117 (IEEE rounds to 0 in case of tie). 118 Using a method that initializes the full mantissa was shown to improve the 119 quality of subsequntly derived normal distribued numbers 120 (Thomas et al. Gaussian random number generators. Acm Comput Surv (2007) 121 vol. 39 (4) pp. 11)) 122 ) 123 $(LI Ziggurat method, a very fast and accurate method was used for both Normal and 124 exp distributed numbers. 125 ) 126 $(LI gamma distribued numbers uses a method recently proposed by Marsaglia and 127 Tsang. The method is very fast, and should be good. 128 My (Fawzi's) feeling is that the transformation h(x)=(1+d*x)^3 might lose 129 a couple of bits of precision in some cases, but it is unclear if this 130 might become visible in (*very* extensive) tests or not. 131 ) 132 the basic source can be easily be changed with something else 133 Efficiency: 134 $(LI very fast methods have been used, and some effort has been put into 135 optimizing some of them, but not all, but the interface has been choosen 136 so that close to optimal implementation can be provided through the same 137 interface. 138 ) 139 $(LI Normal and Exp sources allocated only upon request: no memory waste, but 140 a (*very* small) speed hit, that can be avoided by storing the source in 141 a variable and using it (not going through the RandomG) 142 ) 143 ) 144 Annoyances: 145 $(UL 146 $(LI I have added two "next" methods to RandomG for backward compatibility 147 reasons, and the .instance from Random has been 148 replaced by the "rand" object. The idea behind this is that RandomG is 149 a template and rand it should be shared across all templates. 150 If the name rand is considered bad one could change it. 151 I kept .instance static method that returns rand, so this remain a dropin 152 replacement of the old random. 153 ) 154 $(LI You cannot initialize a static array directly, this because randomize is 155 declared like this: 156 --- 157 U randomize(U)(ref U a) { } 158 --- 159 and a static array cannot be passed by reference. Removing the ref would 160 make arrays initialized, and scalar not, which is much worse. 161 ) 162 ) 163 164 copyright: Copyright (c) 2008. Fawzi Mohamed 165 license: BSD style: $(LICENSE) 166 version: Initial release: July 2008 167 author: Fawzi Mohamed 168 169 *******************************************************************************/ 170 module tango.math.random.Random; 171 import tango.math.random.engines.URandom; 172 import tango.math.random.engines.KissCmwc; 173 import tango.math.random.engines.ArraySource; 174 import tango.math.random.engines.Sync; 175 import tango.math.random.engines.Twister; 176 import tango.math.random.NormalSource; 177 import tango.math.random.ExpSource; 178 import tango.math.Math; 179 import tango.core.Traits; 180 181 // ----- templateFu begin -------- 182 /// compile time integer power 183 private T ctfe_powI(T)(T x,int p){ 184 T xx=cast(T)1; 185 if (p<0){ 186 p=-p; 187 x=1/x; 188 } 189 for (int i=0;i<p;++i) 190 xx*=x; 191 return xx; 192 } 193 // ----- templateFu end -------- 194 195 version (Win32) { 196 private extern(Windows) int QueryPerformanceCounter (ulong *); 197 } 198 version (Posix) { 199 private import tango.stdc.posix.sys.time; 200 } 201 202 version(darwin) { version=has_urandom; } 203 version(linux) { version=has_urandom; } 204 version(solaris){ version=has_urandom; } 205 206 /// if T is a float 207 template isFloat(T){ 208 static if(is(T==float)||is(T==double)||is(T==real)){ 209 enum bool isFloat=true; 210 } else { 211 enum bool isFloat=false; 212 } 213 } 214 215 /// The default engine, a reasonably collision free, with good statistical properties 216 /// not easy to invert, and with a relatively small key (but not too small) 217 alias KissCmwc_32_1 DefaultEngine; 218 219 /// Class that represents a random number generator. 220 /// Normally you should get random numbers either with call-like interface: 221 /// auto r=new Random(); r(i)(j)(k); 222 /// or with randomize 223 /// r.randomize(i); r.randomize(j); r.randomize(k); 224 /// if you use this you should be able to easily switch distribution later, 225 /// as all distributions support this interface, and can be built on the top of RandomG 226 /// auto r2=r.NormalSource!(float)(); r2(i)(j)(k); 227 /// there are utility methods within random for the cases in which you do not 228 /// want to build a special distribution for just a few numbers 229 final class RandomG(SourceT=DefaultEngine) 230 { 231 // uniform random source 232 SourceT source; 233 // normal distributed sources 234 NormalSource!(RandomG,float) normalFloat; 235 NormalSource!(RandomG,double) normalDouble; 236 NormalSource!(RandomG,real) normalReal; 237 // exp distributed sources 238 ExpSource!(RandomG,float) expFloat; 239 ExpSource!(RandomG,double) expDouble; 240 ExpSource!(RandomG,real) expReal; 241 242 /// Creates and seeds a new generator 243 this (bool randomInit=true) 244 { 245 if (randomInit) 246 this.seed(); 247 } 248 249 /// if source.canSeed seeds the generator using the shared rand generator 250 /// (use urandom directly if available?) 251 RandomG seed () 252 { 253 static if(source.canSeed){ 254 source.seed(&rand.uniform!(uint)); 255 } 256 return this; 257 } 258 /// if source.canSeed seeds the generator using the given source of uints 259 RandomG seed (scope uint delegate() seedSource) 260 { 261 static if(source.canSeed){ 262 source.seed(seedSource); 263 } 264 return this; 265 } 266 267 /// compatibility with old Random, deprecate?? 268 uint next(){ 269 return uniform!(uint)(); 270 } 271 /// ditto 272 uint next(uint to){ 273 return uniformR!(uint)(to); 274 } 275 /// ditto 276 uint next(uint from,uint to){ 277 return uniformR2!(uint)(from,to); 278 } 279 /// ditto 280 static RandomG!(Sync!(DefaultEngine)) instance(){ 281 return rand; 282 } 283 //-------- Utility functions to quickly get a uniformly distributed random number ----------- 284 285 /// uniform distribution on the whole range of integer types, and on 286 /// the (0;1) range for floating point types. Floating point guarantees the initialization 287 /// of the full mantissa, but due to rounding effects it might have *very* small 288 /// dependence due to rounding effects on the least significant bit (in case of tie 0 is favored). 289 /// if boundCheck is false in the floating point case bounds might be included (but with a 290 /// lower propability than other numbers) 291 @property 292 T uniform(T,bool boundCheck=true)(){ 293 static if(is(T==uint)) { 294 return source.next(); 295 } else static if (is(T==int) || is(T==short) || is(T==ushort)|| is(T==char) || is(T==byte) || is(T==ubyte)){ 296 union Uint2A{ 297 T t; 298 uint u; 299 } 300 Uint2A a; 301 a.u=source.next(); 302 return a.t; 303 } else static if (is(T==long) || is (T==ulong)){ 304 return cast(T)source.nextL(); 305 } else static if (is(T==bool)){ 306 return cast(bool)(source.next & 1u); // check lowest bit 307 } else static if (is(T==float)||is(T==double)||is(T==real)){ 308 static if (T.mant_dig<30) { 309 enum T halfT=(cast(T)1)/(cast(T)2); 310 enum T fact32=ctfe_powI(halfT,32); 311 enum uint minV=1u<<(T.mant_dig-1); 312 uint nV=source.next(); 313 if (nV>=minV) { 314 T res=nV*fact32; 315 static if (boundCheck){ 316 if (res!=cast(T)1) return res; 317 // 1 due to rounding (<3.e-8), 0 impossible 318 return uniform!(T,boundCheck)(); 319 } else { 320 return res; 321 } 322 } else { // probability 0.00390625 for 24 bit mantissa 323 T scale=fact32; 324 while (nV==0){ // probability 2.3283064365386963e-10 325 nV=source.next(); 326 scale*=fact32; 327 } 328 T res=nV*scale+source.next()*scale*fact32; 329 static if (boundCheck){ 330 if (res!=cast(T)0) return res; 331 return uniform!(T,boundCheck)(); // 0 due to underflow (<1.e-38), 1 impossible 332 } else { 333 return res; 334 } 335 } 336 } else static if (T.mant_dig<62) { 337 enum T halfT=(cast(T)1)/(cast(T)2); 338 enum T fact64=ctfe_powI(halfT,64); 339 enum ulong minV=1UL<<(T.mant_dig-1); 340 ulong nV=source.nextL(); 341 if (nV>=minV) { 342 T res=nV*fact64; 343 static if (boundCheck){ 344 if (res!=cast(T)1) return res; 345 // 1 due to rounding (<1.e-16), 0 impossible 346 return uniform!(T,boundCheck)(); 347 } else { 348 return res; 349 } 350 } else { // probability 0.00048828125 for 53 bit mantissa 351 enum T fact32=ctfe_powI(halfT,32); 352 enum ulong minV2=1UL<<(T.mant_dig-33); 353 if (nV>=minV2){ 354 return ((cast(T)nV)+(cast(T)source.next())*fact32)*fact64; 355 } else { // probability 1.1368683772161603e-13 for 53 bit mantissa 356 T scale=fact64; 357 while (nV==0){ 358 nV=source.nextL(); 359 scale*=fact64; 360 } 361 T res=scale*((cast(T)nV)+(cast(T)source.nextL())*fact64); 362 static if (boundCheck){ 363 if (res!=cast(T)0) return res; 364 // 0 due to underflow (<1.e-307) 365 return uniform!(T,boundCheck)(); 366 } else { 367 return res; 368 } 369 } 370 } 371 } else static if (T.mant_dig<=64){ 372 enum T halfT=(cast(T)1)/(cast(T)2); 373 enum T fact8=ctfe_powI(halfT,8); 374 enum T fact72=ctfe_powI(halfT,72); 375 ubyte nB=source.nextB(); 376 if (nB!=0){ 377 T res=nB*fact8+source.nextL()*fact72; 378 static if (boundCheck){ 379 if (res!=cast(T)1) return res; 380 // 1 due to rounding (<1.e-16), 0 impossible 381 return uniform!(T,boundCheck)(); 382 } else { 383 return res; 384 } 385 } else { // probability 0.00390625 386 enum T fact64=ctfe_powI(halfT,64); 387 T scale=fact8; 388 while (nB==0){ 389 nB=source.nextB(); 390 scale*=fact8; 391 } 392 T res=((cast(T)nB)+(cast(T)source.nextL())*fact64)*scale; 393 static if (boundCheck){ 394 if (res!=cast(T)0) return res; 395 // 0 due to underflow (<1.e-4932), 1 impossible 396 return uniform!(T,boundCheck)(); 397 } else { 398 return res; 399 } 400 } 401 } else { 402 // (T.mant_dig > 64 bits), not so optimized, but works for any size 403 enum T halfT=(cast(T)1)/(cast(T)2); 404 enum T fact32=ctfe_powI(halfT,32); 405 uint nL=source.next(); 406 T fact=fact32; 407 while (nL==0){ 408 fact*=fact32; 409 nL=source.next(); 410 } 411 T res=nL*fact; 412 for (int rBits=T.mant_dig-1;rBits>0;rBits-=32) { 413 fact*=fact32; 414 res+=source.next()*fact; 415 } 416 static if (boundCheck){ 417 if (res!=cast(T)0 && res !=cast(T)1) return res; 418 return uniform!(T,boundCheck)(); // really unlikely... 419 } else { 420 return res; 421 } 422 } 423 } else static if (is(T==cfloat)||is(T==cdouble)||is(T==creal)){ 424 return cast(T)(uniform!(realType!(T))()+1i*uniform!(realType!(T))()); 425 } else static if (is(T==ifloat)||is(T==idouble)||is(T==ireal)){ 426 return cast(T)(1i*uniform!(realType!(T))()); 427 } else static assert(0,T.stringof~" unsupported type for uniform distribution"); 428 } 429 430 /// uniform distribution on the range [0;to) for integer types, and on 431 /// the (0;to) range for floating point types. Same caveat as uniform(T) apply 432 T uniformR(T,bool boundCheck=true)(T to) 433 in { assert(to>0,"empty range");} 434 body { 435 static if (is(T==uint) || is(T==int) || is(T==short) || is(T==ushort) 436 || is(T==char) || is(T==byte) || is(T==ubyte)) 437 { 438 uint d=uint.max/cast(uint)to,dTo=to*d; 439 uint nV=source.next(); 440 if (nV>=dTo){ 441 for (int i=0;i<1000;++i) { 442 nV=source.next(); 443 if (nV<dTo) break; 444 } 445 assert(nV<dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 446 } 447 return cast(T)(nV%to); 448 } else static if (is(T==ulong) || is(T==long)){ 449 ulong d=ulong.max/cast(ulong)to,dTo=to*d; 450 ulong nV=source.nextL(); 451 if (nV>=dTo){ 452 for (int i=0;i<1000;++i) { 453 nV=source.nextL(); 454 if (nV<dTo) break; 455 } 456 assert(nV<dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 457 } 458 return cast(T)(nV%to); 459 } else static if (is(T==float)|| is(T==double)||is(T==real)){ 460 T res=uniform!(T,false)()*to; 461 static if (boundCheck){ 462 if (res!=cast(T)0 && res!=to) return res; 463 return uniformR(to); 464 } else { 465 return res; 466 } 467 } else static assert(0,T.stringof~" unsupported type for uniformR distribution"); 468 } 469 /// uniform distribution on the range (-to;to) for integer types, and on 470 /// the (-to;0)(0;to) range for floating point types if boundCheck is true. 471 /// If boundCheck=false the range changes to [-to;0)u(0;to] with a slightly 472 /// lower propability at the bounds for floating point numbers. 473 /// excludeZero controls if 0 is excluded or not (by default float exclude it, 474 /// ints no). Please note that the probability of 0 in floats is very small due 475 // to the high density of floats close to 0. 476 /// Cannot be used on unsigned types. 477 /// 478 /// In here there is probably one of the few cases where c handling of modulo of negative 479 /// numbers is handy 480 T uniformRSymm(T,bool boundCheck=true, bool excludeZero=isFloat!(T))(T to,int iter=2000) 481 in { assert(to>0,"empty range");} 482 body { 483 static if (is(T==int)|| is(T==short) || is(T==byte)){ 484 int d=int.max/to,dTo=to*d; 485 int nV=cast(int)source.next(); 486 static if (excludeZero){ 487 int isIn=nV<dTo&&nV>-dTo&&nV!=0; 488 } else { 489 int isIn=nV<dTo&&nV>-dTo; 490 } 491 if (isIn){ 492 return cast(T)(nV%to); 493 } else { 494 for (int i=0;i<1000;++i) { 495 nV=cast(int)source.next(); 496 if (nV<dTo && nV>-dTo) break; 497 } 498 assert(nV<dTo && nV>-dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 499 return cast(T)(nV%to); 500 } 501 } else static if (is(T==long)){ 502 long d=long.max/to,dTo=to*d; 503 long nV=cast(long)source.nextL(); 504 static if (excludeZero){ 505 int isIn=nV<dTo&&nV>-dTo&&nV!=0; 506 } else { 507 int isIn=nV<dTo&&nV>-dTo; 508 } 509 if (isIn){ 510 return nV%to; 511 } else { 512 for (int i=0;i<1000;++i) { 513 nV=source.nextL(); 514 if (nV<dTo && nV>-dTo) break; 515 } 516 assert(nV<dTo && nV>-dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 517 return nV%to; 518 } 519 } else static if (is(T==float)||is(T==double)||is(T==real)){ 520 static if (T.mant_dig<30){ 521 enum T halfT=(cast(T)1)/(cast(T)2); 522 enum T fact32=ctfe_powI(halfT,32); 523 enum uint minV=1u<<T.mant_dig; 524 uint nV=source.next(); 525 if (nV>=minV) { 526 T res=nV*fact32*to; 527 static if (boundCheck){ 528 if (res!=to) return (1-2*cast(int)(nV&1u))*res; 529 // to due to rounding (~3.e-8), 0 impossible with normal to values 530 assert(iter>0,"error with the generator, probability < 10^(-8*2000)"); 531 return uniformRSymm(to,iter-1); 532 } else { 533 return (1-2*cast(int)(nV&1u))*res; 534 } 535 } else { // probability 0.008 for 24 bit mantissa 536 T scale=fact32; 537 while (nV==0){ // probability 2.3283064365386963e-10 538 nV=source.next(); 539 scale*=fact32; 540 } 541 uint nV2=source.next(); 542 T res=(cast(T)nV+cast(T)nV2*fact32)*scale*to; 543 static if (excludeZero){ 544 if (res!=cast(T)0) return (1-2*cast(int)(nV&1u))*res; 545 assert(iter>0,"error with the generator, probability < 10^(-8*2000)"); 546 return uniformRSymm(to,iter-1); // 0 due to underflow (<1.e-38), 1 impossible 547 } else { 548 return (1-2*cast(int)(nV&1u))*res; 549 } 550 } 551 } else static if (T.mant_dig<62) { 552 enum T halfT=(cast(T)1)/(cast(T)2); 553 enum T fact64=ctfe_powI(halfT,64); 554 enum ulong minV=1UL<<(T.mant_dig); 555 ulong nV=source.nextL(); 556 if (nV>=minV) { 557 T res=nV*fact64*to; 558 static if (boundCheck){ 559 if (res!=to) return (1-2*cast(int)(nV&1UL))*res; 560 // to due to rounding (<1.e-16), 0 impossible with normal to values 561 assert(iter>0,"error with the generator, probability < 10^(-16*2000)"); 562 return uniformRSymm(to,iter-1); 563 } else { 564 return (1-2*cast(int)(nV&1UL))*res; 565 } 566 } else { // probability 0.00048828125 for 53 bit mantissa 567 enum T fact32=ctfe_powI(halfT,32); 568 enum ulong minV2=1UL<<(T.mant_dig-32); 569 if (nV>=minV2){ 570 uint nV2=source.next(); 571 T res=((cast(T)nV)+(cast(T)nV2)*fact32)*fact64*to; 572 return (1-2*cast(int)(nV2&1UL))*res; // cannot be 0 or to with normal to values 573 } else { // probability 1.1368683772161603e-13 for 53 bit mantissa 574 T scale=fact64; 575 while (nV==0){ 576 nV=source.nextL(); 577 scale*=fact64; 578 } 579 ulong nV2=source.nextL(); 580 T res=to*scale*((cast(T)nV)+(cast(T)nV2)*fact64); 581 static if (excludeZero){ 582 if (res!=cast(T)0) return (1-2*cast(int)(nV2&1UL))*res; 583 // 0 due to underflow (<1.e-307) 584 assert(iter>0,"error with the generator, probability < 10^(-16*2000)"); 585 return uniformRSymm(to,iter-1); 586 } else { 587 return (1-2*cast(int)(nV2&1UL))*res; 588 } 589 } 590 } 591 } else static if (T.mant_dig<=64) { 592 enum T halfT=(cast(T)1)/(cast(T)2); 593 enum T fact8=ctfe_powI(halfT,8); 594 enum T fact72=ctfe_powI(halfT,72); 595 ubyte nB=source.nextB(); 596 if (nB!=0){ 597 ulong nL=source.nextL(); 598 T res=to*(nB*fact8+nL*fact72); 599 static if (boundCheck){ 600 if (res!=to) return (1-2*cast(int)(nL&1UL))*res; 601 // 1 due to rounding (<1.e-16), 0 impossible with normal to values 602 assert(iter>0,"error with the generator, probability < 10^(-16*2000)"); 603 return uniformRSymm(to,iter-1); 604 } else { 605 return (1-2*cast(int)(nL&1UL))*res; 606 } 607 } else { // probability 0.00390625 608 enum T fact64=ctfe_powI(halfT,64); 609 T scale=fact8; 610 while (nB==0){ 611 nB=source.nextB(); 612 scale*=fact8; 613 } 614 ulong nL=source.nextL(); 615 T res=((cast(T)nB)+(cast(T)nL)*fact64)*scale*to; 616 static if (excludeZero){ 617 if (res!=cast(T)0) return ((nL&1UL)?res:-res); 618 // 0 due to underflow (<1.e-4932), 1 impossible 619 assert(iter>0,"error with the generator, probability < 10^(-16*2000)"); 620 return uniformRSymm(to,iter-1); 621 } else { 622 return ((nL&1UL)?res:-res); 623 } 624 } 625 } else { 626 // (T.mant_dig > 64 bits), not so optimized, but works for any size 627 enum T halfT=(cast(T)1)/(cast(T)2); 628 enum T fact32=ctfe_powI(halfT,32); 629 uint nL=source.next(); 630 T fact=fact32; 631 while (nL==0){ 632 fact*=fact32; 633 nL=source.next(); 634 } 635 T res=nL*fact; 636 for (int rBits=T.mant_dig;rBits>0;rBits-=32) { 637 fact*=fact32; 638 nL=source.next(); 639 res+=nL*fact; 640 } 641 static if (boundCheck){ 642 if (res!=to && res!=cast(T)0) return ((nL&1UL)?res:-res); 643 // 1 due to rounding (<1.e-16), 0 impossible with normal to values 644 assert(iter>0,"error with the generator, probability < 10^(-16*2000)"); 645 return uniformRSymm(to,iter-1); 646 } else { 647 return ((nL&1UL)?res:-res); 648 } 649 } 650 } else static assert(0,T.stringof~" unsupported type for uniformRSymm distribution"); 651 } 652 /// uniform distribution [from;to) for integers, and (from;to) for floating point numbers. 653 /// if boundCheck is false the bounds are included in the floating point number distribution. 654 /// the range for int and long is limited to only half the possible range 655 /// (it could be worked around using long aritmethic for int, and doing a carry by hand for long, 656 /// but I think it is seldomly needed, for int you are better off using long when needed) 657 T uniformR2(T,bool boundCheck=true)(T from,T to) 658 in { 659 assert(to>from,"empy range in uniformR2"); 660 static if (is(T==int) || is(T==long)){ 661 assert(from>T.min/2&&to<T.max/2," from..to range too big"); 662 } 663 } 664 body { 665 static if (is(T==int)||is(T==long)||is(T==uint)||is(T==ulong)){ 666 return from+uniformR(to-from); 667 } else static if (is(T==char) || is(T==byte) || is(T==ubyte) || is(T==short) || is(T==ushort)){ 668 int d=cast(int)to-cast(int)from; 669 int nV=uniformR!(int)(d); 670 return cast(T)(nV+cast(int)from); 671 } else static if (is(T==float) || is(T==double) || is(T==real)){ 672 T res=from+(to-from)*uniform!(T,false); 673 static if (boundCheck){ 674 if (res!=from && res!=to) return res; 675 return uniformR2(from,to); 676 } else { 677 return res; 678 } 679 } else static assert(0,T.stringof~" unsupported type for uniformR2 distribution"); 680 } 681 /// returns a random element of the given array (which must be non empty) 682 T uniformEl(T)(const(T[]) arr){ 683 assert(arr.length>0,"array has to be non empty"); 684 return arr[uniformR(arr.length)]; 685 } 686 /// randomizes the given array and returns it (for some types this is potentially 687 /// more efficient, both from the use of random numbers and speedwise) 688 U randomizeUniform(U,bool boundCheck)(ref U a){ 689 static if (is(U S:S[])){ 690 alias BaseTypeOfArrays!(U) T; 691 static if (is(T==byte)||is(T==ubyte)||is(T==char)){ 692 uint val=source.next(); /// begin without value? 693 int rest=4; 694 for (size_t i=0;i<a.length;++i) { 695 if (rest!=0){ 696 a[i]=cast(T)(0xFFu&val); 697 val>>=8; 698 --rest; 699 } else { 700 val=source.next(); 701 a[i]=cast(T)(0xFFu&val); 702 val>>=8; 703 rest=3; 704 } 705 } 706 } else static if (is(T==uint)||is(T==int)){ 707 T* aEnd=a.ptr+a.length; 708 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr) 709 *aPtr=cast(T)(source.next()); 710 } else static if (is(T==ulong)||is(T==long)){ 711 T* aEnd=a.ptr+a.length; 712 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr) 713 *aPtr=cast(T)(source.nextL()); 714 } else static if (is(T==float)|| is(T==double)|| is(T==real)) { 715 // optimize more? not so easy with guaranteed full mantissa initialization 716 T* aEnd=a.ptr+a.length; 717 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 718 *aPtr=uniform!(T,boundCheck)(); 719 } 720 } else static assert(T.stringof~" type not supported by randomizeUniform"); 721 } else { 722 a=uniform!(U,boundCheck)(); 723 } 724 return a; 725 } 726 727 /// randomizes the given array and returns it (for some types this is potentially 728 /// more efficient, both from the use of random numbers and speedwise) 729 U randomizeUniformR(U,V,bool boundCheck=true)(ref U a,V to) 730 in { assert((cast(BaseTypeOfArrays!(U))to)>0,"empty range");} 731 body { 732 alias BaseTypeOfArrays!(U) T; 733 static assert(is(V:T),"incompatible a and to type "~U.stringof~" "~V.stringof); 734 static if (is(U S:S[])){ 735 static if (is(T==uint) || is(T==int) || is(T==char) || is(T==byte) || is(T==ubyte)){ 736 uint d=uint.max/cast(uint)to,dTo=(cast(uint)to)*d; 737 T* aEnd=a.ptr+a.length; 738 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 739 uint nV=source.next(); 740 if (nV<dTo){ 741 *aPtr=cast(T)(nV % cast(uint)to); 742 } else { 743 for (int i=0;i<1000;++i) { 744 nV=source.next(); 745 if (nV<dTo) break; 746 } 747 assert(nV<dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 748 *aPtr=cast(T)(nV % cast(uint)to); 749 } 750 } 751 } else static if (is(T==ulong) || is(T==long)){ 752 ulong d=ulong.max/cast(ulong)to,dTo=(cast(ulong)to)*d; 753 T* aEnd=a.ptr+a.length; 754 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 755 ulong nV=source.nextL(); 756 if (nV<dTo){ 757 el=cast(T)(nV % cast(ulong)to); 758 } else { 759 for (int i=0;i<1000;++i) { 760 nV=source.nextL(); 761 if (nV<dTo) break; 762 } 763 assert(nV<dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 764 el=cast(T)(nV% cast(ulong)to); 765 } 766 } 767 } else static if (is(T==float) || is(T==double) || is(T==real)){ 768 T* aEnd=a.ptr+a.length; 769 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 770 *aPtr=uniformR!(T,boundCheck)(cast(T)to); 771 } 772 } else static assert(0,T.stringof~" unsupported type for uniformR distribution"); 773 } else { 774 a=uniformR!(T,boundCheck)(cast(T)to); 775 } 776 return a; 777 } 778 /// randomizes the given variable and returns it (for some types this is potentially 779 /// more efficient, both from the use of random numbers and speedwise) 780 U randomizeUniformR2(U,V,W,bool boundCheck=true)(ref U a,V from, W to) 781 in { 782 alias BaseTypeOfArrays!(U) T; 783 assert((cast(T)to)>(cast(T)from),"empy range in uniformR2"); 784 static if (is(T==int) || is(T==long)){ 785 assert(from>T.min/2&&to<T.max/2," from..to range too big"); 786 } 787 } 788 body { 789 alias BaseTypeOfArrays!(U) T; 790 static assert(is(V:T),"incompatible a and from type "~U.stringof~" "~V.stringof); 791 static assert(is(W:T),"incompatible a and to type "~U.stringof~" "~W.stringof); 792 static if (is(U S:S[])){ 793 static if (is(T==uint)||is(T==ulong)){ 794 T d=cast(T)to-cast(T)from; 795 T* aEnd=a.ptr+a.length; 796 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 797 *aPtr=from+uniformR!(d)(); 798 } 799 } else if (is(T==char) || is(T==byte) || is(T==ubyte)){ 800 int d=cast(int)to-cast(int)from; 801 T* aEnd=a.ptr+a.length; 802 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 803 *aPtr=cast(T)(uniformR!(d)+cast(int)from); 804 } 805 } else static if (is(T==float) || is(T==double) || is(T==real)){ 806 T* aEnd=a.ptr+a.length; 807 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 808 T res=cast(T)from+(cast(T)to-cast(T)from)*uniform!(T,false); 809 static if (boundCheck){ 810 if (res!=cast(T)from && res!=cast(T)to){ 811 *aPtr=res; 812 } else { 813 *aPtr=uniformR2!(T,boundCheck)(cast(T)from,cast(T)to); 814 } 815 } else { 816 *aPtr=res; 817 } 818 } 819 } else static assert(0,T.stringof~" unsupported type for uniformR2 distribution"); 820 } else { 821 a=uniformR2!(T,boundCheck)(from,to); 822 } 823 return a; 824 } 825 /// randomizes the given variable like uniformRSymm and returns it 826 /// (for some types this is potentially more efficient, both from the use of 827 /// random numbers and speedwise) 828 U randomizeUniformRSymm(U,V,bool boundCheck=true, bool excludeZero=isFloat!(BaseTypeOfArrays!(U))) 829 (ref U a,V to) 830 in { assert((cast(BaseTypeOfArrays!(U))to)>0,"empty range");} 831 body { 832 alias BaseTypeOfArrays!(U) T; 833 static assert(is(V:T),"incompatible a and to type "~U.stringof~" "~V.stringof); 834 static if (is(U S:S[])){ 835 static if (is(T==int)|| is(T==byte)){ 836 int d=int.max/cast(int)to,dTo=(cast(int)to)*d; 837 T* aEnd=a.ptr+a.length; 838 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 839 int nV=cast(int)source.next(); 840 static if (excludeZero){ 841 int isIn=nV<dTo&&nV>-dTo&&nV!=0; 842 } else { 843 int isIn=nV<dTo&&nV>-dTo; 844 } 845 if (isIn){ 846 *aPtr=cast(T)(nV% cast(int)to); 847 } else { 848 for (int i=0;i<1000;++i) { 849 nV=cast(int)source.next(); 850 if (nV<dTo&&nV>-dTo) break; 851 } 852 assert(nV<dTo && nV>-dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 853 *aPtr=cast(T)(nV% cast(int)to); 854 } 855 } 856 } else static if (is(T==long)){ 857 long d=long.max/cast(T)to,dTo=(cast(T)to)*d; 858 long nV=cast(long)source.nextL(); 859 T* aEnd=a.ptr+a.length; 860 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 861 static if (excludeZero){ 862 int isIn=nV<dTo&&nV>-dTo&&nV!=0; 863 } else { 864 int isIn=nV<dTo&&nV>-dTo; 865 } 866 if (isIn){ 867 *aPtr=nV% cast(T)to; 868 } else { 869 for (int i=0;i<1000;++i) { 870 nV=source.nextL(); 871 if (nV<dTo && nV>-dTo) break; 872 } 873 assert(nV<dTo && nV>-dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 874 *aPtr=nV% cast(T)to; 875 } 876 } 877 } else static if (is(T==float)||is(T==double)||is(T==real)){ 878 T* aEnd=a.ptr+a.length; 879 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 880 *aPtr=uniformRSymm!(T,boundCheck,excludeZero)(cast(T)to); 881 } 882 } else static assert(0,T.stringof~" unsupported type for uniformRSymm distribution"); 883 } else { 884 a=uniformRSymm!(T,boundCheck,excludeZero)(cast(T)to); 885 } 886 return a; 887 } 888 889 /// returns another (mostly indipendent, depending on seed size) random generator 890 RandG spawn(RandG=RandomG)(){ 891 RandG res=new RandG(false); 892 synchronized(this){ 893 res.seed(&uniform!(uint)); 894 } 895 return res; 896 } 897 898 // ------- structs for uniform distributions ----- 899 /// uniform distribution on the whole range for integers, and on (0;1) for floats 900 /// with boundCheck=true this is equivalent to r itself, here just for completness 901 struct UniformDistribution(T,bool boundCheck){ 902 RandomG r; 903 static UniformDistribution create(RandomG r){ 904 UniformDistribution res; 905 res.r=r; 906 return res; 907 } 908 /// chainable call style initialization of variables (thorugh a call to randomize) 909 UniformDistribution opCall(U,S...)(ref U a,S args){ 910 randomize(a,args); 911 return this; 912 } 913 /// returns a random number 914 T getRandom(){ 915 return r.uniform!(T,boundCheck)(); 916 } 917 /// initialize el 918 U randomize(U)(ref U a){ 919 return r.randomizeUniform!(U,boundCheck)(a); 920 } 921 } 922 923 /// uniform distribution on the subrange [0;to) for integers, (0;to) for floats 924 struct UniformRDistribution(T,bool boundCheck){ 925 T to; 926 RandomG r; 927 /// initializes the probability distribution 928 static UniformRDistribution create(RandomG r,T to){ 929 UniformRDistribution res; 930 res.r=r; 931 res.to=to; 932 return res; 933 } 934 /// chainable call style initialization of variables (thorugh a call to randomize) 935 UniformRDistribution opCall(U)(ref U a){ 936 randomize(a); 937 return this; 938 } 939 /// returns a random number 940 T getRandom(){ 941 return r.uniformR!(T,boundCheck)(to); 942 } 943 /// initialize el 944 U randomize(U)(ref U a){ 945 return r.randomizeUniformR!(U,T,boundCheck)(a,to); 946 } 947 } 948 949 /// uniform distribution on the subrange (-to;to) for integers, (-to;0)u(0;to) for floats 950 /// excludeZero controls if the zero should be excluded, boundCheck if the boundary should 951 /// be excluded for floats 952 struct UniformRSymmDistribution(T,bool boundCheck=true,bool excludeZero=isFloat!(T)){ 953 T to; 954 RandomG r; 955 /// initializes the probability distribution 956 static UniformRSymmDistribution create(RandomG r,T to){ 957 UniformRSymmDistribution res; 958 res.r=r; 959 res.to=to; 960 return res; 961 } 962 /// chainable call style initialization of variables (thorugh a call to randomize) 963 UniformRSymmDistribution opCall(U)(ref U a){ 964 randomize(a); 965 return this; 966 } 967 /// returns a random number 968 T getRandom(){ 969 return r.uniformRSymm!(T,boundCheck,excludeZero)(to); 970 } 971 /// initialize el 972 U randomize(U)(ref U a){ 973 return r.randomizeUniformRSymm!(U,T,boundCheck)(a,to); 974 } 975 } 976 977 /// uniform distribution on the subrange (-to;to) for integers, (0;to) for floats 978 struct UniformR2Distribution(T,bool boundCheck){ 979 T from,to; 980 RandomG r; 981 /// initializes the probability distribution 982 static UniformR2Distribution create(RandomG r,T from, T to){ 983 UniformR2Distribution res; 984 res.r=r; 985 res.from=from; 986 res.to=to; 987 return res; 988 } 989 /// chainable call style initialization of variables (thorugh a call to randomize) 990 UniformR2Distribution opCall(U,S...)(ref U a,S args){ 991 randomize(a,args); 992 return this; 993 } 994 /// returns a random number 995 T getRandom(){ 996 return r.uniformR2!(T,boundCheck)(from,to); 997 } 998 /// initialize a 999 U randomize(U)(ref U a){ 1000 return r.randomizeUniformR2!(U,T,T,boundCheck)(a,from,to); 1001 } 1002 } 1003 1004 // ---------- gamma distribution, move to a separate module? -------- 1005 /// gamma distribution f=x^(alpha-1)*exp(-x/theta)/(gamma(alpha)*theta^alpha) 1006 /// alpha has to be bigger than 1, for alpha<1 use gammaD(alpha)=gammaD(alpha+1)*pow(r.uniform!(T),1/alpha) 1007 /// from Marsaglia and Tsang, ACM Transaction on Mathematical Software, Vol. 26, N. 3 1008 /// 2000, p 363-372 1009 struct GammaDistribution(T){ 1010 RandomG r; 1011 T alpha; 1012 T theta; 1013 static GammaDistribution create(RandomG r,T alpha=cast(T)1,T theta=cast(T)1){ 1014 GammaDistribution res; 1015 res.r=r; 1016 res.alpha=alpha; 1017 res.theta=theta; 1018 assert(alpha>=cast(T)1,"implemented only for alpha>=1"); 1019 return res; 1020 } 1021 /// chainable call style initialization of variables (thorugh a call to randomize) 1022 GammaDistribution opCall(U,S...)(ref U a,S args){ 1023 randomize(a,args); 1024 return this; 1025 } 1026 /// returns a single random number 1027 T getRandom(T a=alpha,T t=theta) 1028 in { assert(a>=cast(T)1,"implemented only for alpha>=1"); } 1029 body { 1030 T d=a-(cast(T)1)/(cast(T)3); 1031 T c=(cast(T)1)/sqrt(d*cast(T)9); 1032 auto n=r.normalSource!(T)(); 1033 for (;;) { 1034 do { 1035 T x=n.getRandom(); 1036 T v=c*x+cast(T)1; 1037 v=v*v*v; // might underflow (in extreme situations) so it is in the loop 1038 } while (v<=0); 1039 T u=r.uniform!(T)(); 1040 if (u<1-(cast(T)0.331)*(x*x)*(x*x)) return t*d*v; 1041 if (log(u)< x*x/2+d*(1-v+log(v))) return t*d*v; 1042 } 1043 } 1044 /// initializes b with gamma distribued random numbers 1045 U randomize(U)(ref U b,T a=alpha,T t=theta){ 1046 static if (is(U S:S[])) { 1047 alias BaseTypeOfArrays!(U) T; 1048 T* bEnd=b.ptr+b.length; 1049 for (T* bPtr=b.ptr;bPtr!=bEnd;++bPtr){ 1050 *bPtr=cast(BaseTypeOfArrays!(U)) getRandom(a,t); 1051 } 1052 } else { 1053 b=cast(U) getRandom(a,t); 1054 } 1055 return b; 1056 } 1057 /// maps op on random numbers (of type T) and initializes b with it 1058 U randomizeOp(U,S)(S delegate(T)op, ref U b,T a=alpha, T t=theta){ 1059 static if(is(U S:S[])){ 1060 alias BaseTypeOfArrays!(U) T; 1061 T* bEnd=b.ptr+b.length; 1062 for (T* bPtr=b.ptr;bPtr!=bEnd;++bPtr){ 1063 *bPtr=cast(BaseTypeOfArrays!(U))op(getRandom(a,t)); 1064 } 1065 } else { 1066 b=cast(U)op(getRandom(a)); 1067 } 1068 return b; 1069 } 1070 } 1071 1072 //-------- various distributions available ----------- 1073 1074 /// generators of normal numbers (sigma=1,mu=0) of the given type 1075 /// f=exp(-x*x/(2*sigma^2))/(sqrt(2 pi)*sigma) 1076 NormalSource!(RandomG,T) normalSource(T)(){ 1077 static if(is(T==float)){ 1078 if (!normalFloat) normalFloat=new NormalSource!(RandomG,T)(this); 1079 return normalFloat; 1080 } else static if (is(T==double)){ 1081 if (!normalDouble) normalDouble=new NormalSource!(RandomG,T)(this); 1082 return normalDouble; 1083 } else static if (is(T==real)){ 1084 if (!normalReal) normalReal=new NormalSource!(RandomG,T)(this); 1085 return normalReal; 1086 } else static assert(0,T.stringof~" no normal source implemented"); 1087 } 1088 1089 /// generators of exp distribued numbers (beta=1) of the given type 1090 /// f=1/beta*exp(-x/beta) 1091 ExpSource!(RandomG,T) expSource(T)(){ 1092 static if(is(T==float)){ 1093 if (!expFloat) expFloat=new ExpSource!(RandomG,T)(this); 1094 return expFloat; 1095 } else static if (is(T==double)){ 1096 if (!expDouble) expDouble=new ExpSource!(RandomG,T)(this); 1097 return expDouble; 1098 } else static if (is(T==real)){ 1099 if (!expReal) expReal=new ExpSource!(RandomG,T)(this); 1100 return expReal; 1101 } else static assert(0,T.stringof~" no exp source implemented"); 1102 } 1103 1104 /// generators of normal numbers with a different default sigma/mu 1105 /// f=exp(-x*x/(2*sigma^2))/(sqrt(2 pi)*sigma) 1106 NormalSource!(RandomG,T).NormalDistribution normalD(T)(T sigma=cast(T)1,T mu=cast(T)0){ 1107 return normalSource!(T)().normalD(sigma,mu); 1108 } 1109 /// exponential distribued numbers with a different default beta 1110 /// f=1/beta*exp(-x/beta) 1111 ExpSource!(RandomG,T).ExpDistribution expD(T)(T beta){ 1112 return expSource!(T)().expD(beta); 1113 } 1114 /// gamma distribued numbers with the given default alpha 1115 GammaDistribution!(T) gammaD(T)(T alpha=cast(T)1,T theta=cast(T)1){ 1116 return GammaDistribution!(T).create(this,alpha,theta); 1117 } 1118 1119 /// uniform distribution on the whole integer range, and on (0;1) for floats 1120 /// should return simply this?? 1121 UniformDistribution!(T,true) uniformD(T)(){ 1122 return UniformDistribution!(T,true).create(this); 1123 } 1124 /// uniform distribution on the whole integer range, and on [0;1] for floats 1125 UniformDistribution!(T,false) uniformBoundsD(T)(){ 1126 return UniformDistribution!(T,false).create(this); 1127 } 1128 /// uniform distribution [0;to) for ints, (0:to) for reals 1129 UniformRDistribution!(T,true) uniformRD(T)(T to){ 1130 return UniformRDistribution!(T,true).create(this,to); 1131 } 1132 /// uniform distribution [0;to) for ints, [0:to] for reals 1133 UniformRDistribution!(T,false) uniformRBoundsD(T)(T to){ 1134 return UniformRDistribution!(T,false).create(this,to); 1135 } 1136 /// uniform distribution (-to;to) for ints and (-to;0)u(0;to) for reals 1137 UniformRSymmDistribution!(T,true,isFloat!(T)) uniformRSymmD(T)(T to){ 1138 return UniformRSymmDistribution!(T,true,isFloat!(T)).create(this,to); 1139 } 1140 /// uniform distribution (-to;to) for ints and [-to;0)u(0;to] for reals 1141 UniformRSymmDistribution!(T,false,isFloat!(T)) uniformRSymmBoundsD(T)(T to){ 1142 return UniformRSymmDistribution!(T,false,isFloat!(T)).create(this,to); 1143 } 1144 /// uniform distribution [from;to) for ints and (from;to) for reals 1145 UniformR2Distribution!(T,true) uniformR2D(T)(T from, T to){ 1146 return UniformR2Distribution!(T,true).create(this,from,to); 1147 } 1148 /// uniform distribution [from;to) for ints and [from;to] for reals 1149 UniformR2Distribution!(T,false) uniformR2BoundsD(T)(T from, T to){ 1150 return UniformR2Distribution!(T,false).create(this,from,to); 1151 } 1152 1153 // -------- Utility functions for other distributions ------- 1154 // add also the corresponding randomize functions? 1155 1156 /// returns a normal distribued number 1157 T normal(T)(){ 1158 return normalSource!(T)().getRandom(); 1159 } 1160 /// returns a normal distribued number with the given sigma 1161 T normalSigma(T)(T sigma){ 1162 return normalSource!(T)().getRandom(sigma); 1163 } 1164 /// returns a normal distribued number with the given sigma and mu 1165 T normalSigmaMu(T)(T sigma,T mu){ 1166 return normalSource!(T)().getRandom(sigma,mu); 1167 } 1168 1169 /// returns an exp distribued number 1170 T exp(T)(){ 1171 return expSource!(T)().getRandom(); 1172 } 1173 /// returns an exp distribued number with the given scale beta 1174 T expBeta(T)(T beta){ 1175 return expSource!(T)().getRandom(beta); 1176 } 1177 1178 /// returns a gamma distribued number 1179 /// from Marsaglia and Tsang, ACM Transaction on Mathematical Software, Vol. 26, N. 3 1180 /// 2000, p 363-372 1181 T gamma(T)(T alpha=cast(T)1,T sigma=cast(T)1) 1182 in { assert(alpha>=cast(T)1,"implemented only for alpha>=1"); } 1183 body { 1184 auto n=normalSource!(T); 1185 T d=alpha-(cast(T)1)/(cast(T)3); 1186 T c=(cast(T)1)/sqrt(d*cast(T)9); 1187 for (;;) { 1188 T x,v; 1189 do { 1190 x=n.getRandom(); 1191 v=c*x+cast(T)1; 1192 v=v*v*v; // might underflow (in extreme situations) so it is in the loop 1193 } while (v<=0); 1194 T u=uniform!(T)(); 1195 if (u<1-(cast(T)0.331)*(x*x)*(x*x)) return sigma*d*v; 1196 if (log(u)< x*x/2+d*(1-v+log(v))) return sigma*d*v; 1197 } 1198 } 1199 // --------------- 1200 1201 /// writes the current status in a string 1202 override string toString(){ 1203 return source.toString().idup; 1204 } 1205 /// reads the current status from a string (that should have been trimmed) 1206 /// returns the number of chars read 1207 size_t fromString(const(char[]) s){ 1208 return source.fromString(s); 1209 } 1210 1211 // make this by default a uniformRandom number generator 1212 /// chainable call style initialization of variables (thorugh a call to randomize) 1213 RandomG opCall(U)(ref U a){ 1214 randomize(a); 1215 return this; 1216 } 1217 /// returns a random number 1218 T getRandom(T)(){ 1219 return uniform!(T,true)(); 1220 } 1221 /// initialize el 1222 U randomize(U)(ref U a){ 1223 return randomizeUniform!(U,true)(a); 1224 } 1225 1226 } // end class RandomG 1227 1228 /// make the default random number generator type 1229 /// (a non threadsafe random number generator) easily available 1230 /// you can safely expect a new instance of this to be indipendent from all the others 1231 alias RandomG!() Random; 1232 /// default threadsafe random number generator type 1233 alias RandomG!(Sync!(DefaultEngine)) RandomSync; 1234 1235 /// shared locked (threadsafe) random number generator 1236 /// initialized with urandom if available, with time otherwise 1237 static __gshared RandomSync rand; 1238 shared static this () 1239 { 1240 rand = new RandomSync(false); 1241 version(has_urandom){ 1242 URandom r; 1243 rand.seed(&r.next); 1244 } else { 1245 ulong s; 1246 version (Posix){ 1247 timeval tv; 1248 gettimeofday (&tv, null); 1249 s = tv.tv_usec; 1250 } else version (Win32) { 1251 QueryPerformanceCounter (&s); 1252 } 1253 uint[2] a; 1254 a[0]= cast(uint)(s & 0xFFFF_FFFFUL); 1255 a[1]= cast(uint)(s>>32); 1256 rand.seed(&(ArraySource(a).next)); 1257 } 1258 } 1259 1260 debug(UnitTest){ 1261 import tango.math.random.engines.KISS; 1262 import tango.math.random.engines.CMWC; 1263 import tango.stdc.stdio:printf; 1264 import tango.io.Stdout; 1265 1266 /// very simple statistal test, mean within maxOffset, and maximum/minimum at least minmax/maxmin 1267 bool checkMean(T)(T[] a, real maxmin, real minmax, real expectedMean, real maxOffset,bool alwaysPrint=false,bool checkB=false){ 1268 T minV,maxV; 1269 real meanV=0.0L; 1270 if (a.length>0){ 1271 minV=a[0]; 1272 maxV=a[0]; 1273 foreach (el;a){ 1274 assert(!checkB || (cast(T)0<el && el<cast(T)1),"el out of bounds"); 1275 if (el<minV) minV=el; 1276 if (el>maxV) maxV=el; 1277 meanV+=cast(real)el; 1278 } 1279 meanV/=cast(real)a.length; 1280 bool printM=false; 1281 if (cast(real)minV>maxmin) printM=true; 1282 if (cast(real)maxV<minmax) printM=true; 1283 if (expectedMean-maxOffset>meanV || meanV>expectedMean+maxOffset) printM=true; 1284 if (printM){ 1285 version (GNU){ 1286 printf("WARNING tango.math.Random statistic is strange: %.*s[%d] %Lg %Lg %Lg\n\0",cast(int)T.stringof.length,T.stringof.ptr,a.length,cast(real)minV,meanV,cast(real)maxV); 1287 } else { 1288 printf("WARNING tango.math.Random statistic is strange: %.*s[%d] %Lg %Lg %Lg\n\0",cast(int)T.stringof.length,T.stringof.ptr,a.length,cast(real)minV,meanV,cast(real)maxV); 1289 } 1290 } else if (alwaysPrint) { 1291 version (GNU){ 1292 printf("tango.math.Random statistic: %.*s[%d] %Lg %Lg %Lg\n\0",cast(int)T.stringof.length,T.stringof.ptr,a.length,cast(real)minV,meanV,cast(real)maxV); 1293 } else { 1294 printf("tango.math.Random statistic: %.*s[%d] %Lg %Lg %Lg\n\0",cast(int)T.stringof.length,T.stringof.ptr,a.length,cast(real)minV,meanV,cast(real)maxV); 1295 } 1296 } 1297 return printM; 1298 } 1299 assert(0); 1300 } 1301 1302 /// check a given generator both on the whole array, and on each element separately 1303 bool doTests(RandG,Arrays...)(RandG r,real maxmin, real minmax, real expectedMean, real maxOffset,bool alwaysPrint,bool checkB, Arrays arrs){ 1304 bool gFail=false; 1305 foreach (i,TA;Arrays){ 1306 alias BaseTypeOfArrays!(TA) T; 1307 // all together 1308 r(arrs[i]); 1309 bool fail=checkMean!(T)(arrs[i],maxmin,minmax,expectedMean,maxOffset,alwaysPrint,checkB); 1310 // one by one 1311 foreach (ref el;arrs[i]){ 1312 r(el); 1313 } 1314 fail |= checkMean!(T)(arrs[i],maxmin,minmax,expectedMean,maxOffset,alwaysPrint,checkB); 1315 gFail |= fail; 1316 } 1317 return gFail; 1318 } 1319 1320 void testRandSource(RandS)(){ 1321 auto r=new RandomG!(RandS)(); 1322 // r.fromString("KISS99_b66dda10_49340130_8f3bf553_224b7afa_00000000_00000000"); // to reproduce a given test... 1323 const(char[]) initialState=r.toString(); // so that you can reproduce things... 1324 bool allStats=false; // set this to true to show all statistics (helpful to track an error) 1325 try{ 1326 r.uniform!(uint)(); 1327 r.uniform!(ubyte)(); 1328 r.uniform!(ulong)(); 1329 int count=10_000; 1330 for (int i=count;i!=0;--i){ 1331 float f=r.uniform!(float)(); 1332 assert(0<f && f<1,"float out of bounds"); 1333 double d=r.uniform!(double)(); 1334 assert(0<d && d<1,"double out of bounds"); 1335 real rr=r.uniform!(real)(); 1336 assert(0<rr && rr<1,"double out of bounds"); 1337 } 1338 // checkpoint status (str) 1339 const(char[]) status=r.toString(); 1340 uint tVal=r.uniform!(uint)(); 1341 ubyte t2Val=r.uniform!(ubyte)(); 1342 ulong t3Val=r.uniform!(ulong)(); 1343 1344 byte[1000] barr; 1345 ubyte[1000] ubarr; 1346 uint[1000] uiarr; 1347 int[1000] iarr; 1348 float[1000] farr; 1349 double[1000]darr; 1350 real[1000] rarr; 1351 byte[] barr2=barr[]; 1352 ubyte[] ubarr2=ubarr[]; 1353 uint[] uiarr2=uiarr[]; 1354 int[] iarr2=iarr[]; 1355 float[] farr2=farr[]; 1356 double[]darr2=darr[]; 1357 real[] rarr2=rarr[]; 1358 1359 bool fail=false,gFail=false; 1360 if (allStats) Stdout("Uniform").newline; 1361 fail =doTests(r,-100.0L,100.0L,0.0L,20.0L,allStats,false,barr2); 1362 fail|=doTests(r,100.0L,155.0L,127.5L,20.0L,allStats,false,ubarr2); 1363 fail|=doTests(r,0.25L*cast(real)(uint.max),0.75L*cast(real)uint.max, 1364 0.5L*uint.max,0.2L*uint.max,allStats,false,uiarr2); 1365 fail|=doTests(r,0.5L*cast(real)int.min,0.5L*cast(real)int.max, 1366 0.0L,0.2L*uint.max,allStats,false,iarr2); 1367 fail|=doTests(r,0.2L,0.8L,0.5L,0.2L,allStats,true,farr2,darr2,rarr2); 1368 gFail|=fail; 1369 if (fail) Stdout("... with Uniform distribution"); 1370 1371 if (allStats) Stdout("UniformD").newline; 1372 fail =doTests(r.uniformD!(int)(),-100.0L,100.0L,0.0L,20.0L,allStats,false,barr2); 1373 fail|=doTests(r.uniformD!(int)(),100.0L,155.0L,127.5L,20.0L,allStats,false,ubarr2); 1374 fail|=doTests(r.uniformD!(int)(),0.25L*cast(real)(uint.max),0.75L*cast(real)uint.max, 1375 0.5L*uint.max,0.2L*uint.max,allStats,false,uiarr2); 1376 fail|=doTests(r.uniformD!(real)(),0.5L*cast(real)int.min,0.5L*cast(real)int.max, 1377 0.0L,0.2L*uint.max,allStats,false,iarr2); 1378 fail|=doTests(r.uniformD!(real)(),0.2L,0.8L,0.5L,0.2L,allStats,true,farr2,darr2,rarr2); 1379 gFail|=fail; 1380 if (fail) Stdout("... with UniformD distribution"); 1381 1382 if (allStats) Stdout("UniformBoundsD").newline; 1383 fail =doTests(r.uniformBoundsD!(int)(),-100.0L,100.0L,0.0L,20.0L,allStats,false,barr2); 1384 fail|=doTests(r.uniformBoundsD!(int)(),100.0L,155.0L,127.5L,20.0L,allStats,false,ubarr2); 1385 fail|=doTests(r.uniformBoundsD!(int)(),0.25L*cast(real)(uint.max),0.75L*cast(real)uint.max, 1386 0.5L*uint.max,0.2L*uint.max,allStats,false,uiarr2); 1387 fail|=doTests(r.uniformBoundsD!(int)(),0.5L*cast(real)int.min,0.5L*cast(real)int.max, 1388 0.0L,0.2L*uint.max,allStats,false,iarr2); 1389 fail|=doTests(r.uniformBoundsD!(int)(),0.2L,0.8L,0.5L,0.2L,allStats,false,farr2,darr2,rarr2); 1390 gFail|=fail; 1391 if (fail) Stdout("... with UniformBoundsD distribution"); 1392 1393 if (allStats) Stdout("UniformRD").newline; 1394 fail =doTests(r.uniformRD(cast(byte)101),25.0L,75.0L,50.0L,15.0L,allStats,false,barr2); 1395 fail|=doTests(r.uniformRD(cast(ubyte)201),50.0L,150.0L,100.0L,20.0L,allStats,false,ubarr2); 1396 fail|=doTests(r.uniformRD(1001u),250.0L,750.0L,500.0L,100.0L,allStats,false,uiarr2); 1397 fail|=doTests(r.uniformRD(1001 ),250.0L,750.0L,500.0L,100.0L,allStats,false,iarr2); 1398 fail|=doTests(r.uniformRD(1000.0L),250.0L,750.0L,500.0L,100.0L, 1399 allStats,false,farr2,darr2,rarr2); 1400 fail|=doTests(r.uniformRD(1.0L),0.2L,0.8L,0.5L,0.2L,allStats,true,farr2,darr2,rarr2); 1401 gFail|=fail; 1402 if (fail) Stdout("... with uniformRD distribution"); 1403 1404 if (allStats) Stdout("UniformRBoundsD").newline; 1405 fail =doTests(r.uniformRBoundsD(cast(byte)101),25.0L,75.0L,50.0L,15.0L,allStats,false,barr2); 1406 fail|=doTests(r.uniformRBoundsD(cast(ubyte)201),50.0L,150.0L,100.0L,20.0L,allStats,false,ubarr2); 1407 fail|=doTests(r.uniformRBoundsD(1001u),250.0L,750.0L,500.0L,100.0L,allStats,false,uiarr2); 1408 fail|=doTests(r.uniformRBoundsD(1001 ),250.0L,750.0L,500.0L,100.0L,allStats,false,iarr2); 1409 fail|=doTests(r.uniformRBoundsD(1000.0L),250.0L,750.0L,500.0L,100.0L, 1410 allStats,false,farr2,darr2,rarr2); 1411 gFail|=fail; 1412 if (fail) Stdout("... with uniformRBoundsD distribution"); 1413 1414 if (allStats) Stdout("Rsymm").newline; 1415 fail =doTests(r.uniformRSymmD!(byte)(cast(byte)100), 1416 -40.0L,40.0L,0.0L,30.0L,allStats,false,barr2); 1417 fail|=doTests(r.uniformRSymmD!(int)(1000), 1418 -300.0L,300.0L,0.0L,200.0L,allStats,false,iarr2); 1419 fail|=doTests(r.uniformRSymmD!(real)(1.0L), 1420 -0.3L,0.3L,0.0L,0.3L,allStats,false,farr2,darr2,rarr2); 1421 gFail|=fail; 1422 if (fail) Stdout("... with Rsymm distribution"); 1423 1424 if (allStats) Stdout("RsymmBounds").newline; 1425 fail =doTests(r.uniformRSymmBoundsD!(byte)(cast(byte)100), 1426 -40.0L,40.0L,0.0L,30.0L,allStats,false,barr2); 1427 fail|=doTests(r.uniformRSymmBoundsD!(int)(1000), 1428 -300.0L,300.0L,0.0L,200.0L,allStats,false,iarr2); 1429 fail|=doTests(r.uniformRSymmBoundsD!(real)(1.0L), 1430 -0.3L,0.3L,0.0L,0.3L,allStats,false,farr2,darr2,rarr2); 1431 gFail|=fail; 1432 if (fail) Stdout("... with RsymmBounds distribution"); 1433 1434 if (allStats) Stdout("Norm").newline; 1435 fail =doTests(r.normalSource!(float)(),-0.5L,0.5L,0.0L,1.0L, 1436 allStats,false,farr2,darr2,rarr2); 1437 fail|=doTests(r.normalSource!(double)(),-0.5L,0.5L,0.0L,1.0L, 1438 allStats,false,farr2,darr2,rarr2); 1439 fail|=doTests(r.normalSource!(real)(),-0.5L,0.5L,0.0L,1.0L, 1440 allStats,false,farr2,darr2,rarr2); 1441 fail|=doTests(r.normalD!(real)(0.5L,5.0L),4.5L,5.5L,5.0L,0.5L, 1442 allStats,false,farr2,darr2,rarr2); 1443 gFail|=fail; 1444 if (fail) Stdout("... with Normal distribution"); 1445 1446 if (allStats) Stdout("Exp").newline; 1447 fail =doTests(r.expSource!(float)(),0.8L,2.0L,1.0L,1.0L, 1448 allStats,false,farr2,darr2,rarr2); 1449 fail|=doTests(r.expSource!(double)(),0.8L,2.0L,1.0L,1.0L, 1450 allStats,false,farr2,darr2,rarr2); 1451 fail|=doTests(r.expSource!(real)(),0.8L,2.0L,1.0L,1.0L, 1452 allStats,false,farr2,darr2,rarr2); 1453 fail|=doTests(r.expD!(real)(5.0L),1.0L,7.0L,5.0L,1.0L, 1454 allStats,false,farr2,darr2,rarr2); 1455 gFail|=fail; 1456 if (fail) Stdout("... with Exp distribution"); 1457 1458 uint seed = 0; 1459 r.seed({ return 2*(seed++); }); 1460 auto v1 = r.uniform!(int)(); 1461 1462 seed = 0; 1463 r.seed({ return 2*(seed++); }); 1464 auto v2 = r.uniform!(int)(); 1465 1466 assert(v1 == v2, "Re-seed failure: " ~ RandS.stringof); 1467 1468 r.fromString(status); 1469 assert(r.uniform!(uint)()==tVal,"restoring of status from str failed"); 1470 assert(r.uniform!(ubyte)()==t2Val,"restoring of status from str failed"); 1471 assert(r.uniform!(ulong)()==t3Val,"restoring of status from str failed"); 1472 assert(!gFail,"Random.d failure"); 1473 } catch(Exception e) { 1474 Stdout(initialState).newline; 1475 throw e; 1476 } 1477 } 1478 1479 unittest { 1480 testRandSource!(Kiss99)(); 1481 testRandSource!(CMWC_default)(); 1482 testRandSource!(KissCmwc_default)(); 1483 testRandSource!(Twister)(); 1484 testRandSource!(DefaultEngine)(); 1485 testRandSource!(Sync!(DefaultEngine))(); 1486 } 1487 1488 }