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