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 return cast(T)(uniform!(realType!(T))()+1i*uniform!(realType!(T))()); 430 } else static if (is(T==ifloat)||is(T==idouble)||is(T==ireal)){ 431 return cast(T)(1i*uniform!(realType!(T))()); 432 } else static assert(0,T.stringof~" unsupported type for uniform distribution"); 433 } 434 435 /// uniform distribution on the range [0;to$(RPAREN) for integer types, and on 436 /// the (0;to) range for floating point types. Same caveat as uniform(T) apply 437 T uniformR(T,bool boundCheck=true)(T to) 438 { 439 verify(to>0,"empty range"); 440 static if (is(T==uint) || is(T==int) || is(T==short) || is(T==ushort) 441 || is(T==char) || is(T==byte) || is(T==ubyte)) 442 { 443 uint d=uint.max/cast(uint)to,dTo=to*d; 444 uint nV=source.next; 445 if (nV>=dTo){ 446 for (int i=0;i<1000;++i) { 447 nV=source.next; 448 if (nV<dTo) break; 449 } 450 verify(nV<dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 451 } 452 return cast(T)(nV%to); 453 } else static if (is(T==ulong) || is(T==long)){ 454 ulong d=ulong.max/cast(ulong)to,dTo=to*d; 455 ulong nV=source.nextL; 456 if (nV>=dTo){ 457 for (int i=0;i<1000;++i) { 458 nV=source.nextL; 459 if (nV<dTo) break; 460 } 461 verify(nV<dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 462 } 463 return cast(T)(nV%to); 464 } else static if (is(T==float)|| is(T==double)||is(T==real)){ 465 T res=uniform!(T,false)*to; 466 static if (boundCheck){ 467 if (res!=cast(T)0 && res!=to) return res; 468 return uniformR(to); 469 } else { 470 return res; 471 } 472 } else static assert(0,T.stringof~" unsupported type for uniformR distribution"); 473 } 474 /// uniform distribution on the range (-to;to) for integer types, and on 475 /// the (-to;0)(0;to) range for floating point types if boundCheck is true. 476 /// If boundCheck=false the range changes to [-to;0$(RPAREN)u$(LPAREN)0;to] with a slightly 477 /// lower propability at the bounds for floating point numbers. 478 /// excludeZero controls if 0 is excluded or not (by default float exclude it, 479 /// ints no). Please note that the probability of 0 in floats is very small due 480 // to the high density of floats close to 0. 481 /// Cannot be used on unsigned types. 482 /// 483 /// In here there is probably one of the few cases where c handling of modulo of negative 484 /// numbers is handy 485 T uniformRSymm(T,bool boundCheck=true, bool excludeZero=isFloat!(T))(T to,int iter=2000) 486 { 487 verify(to>0,"empty range"); 488 static if (is(T==int)|| is(T==short) || is(T==byte)){ 489 int d=int.max/to,dTo=to*d; 490 int nV=cast(int)source.next; 491 static if (excludeZero){ 492 int isIn=nV<dTo&&nV>-dTo&&nV!=0; 493 } else { 494 int isIn=nV<dTo&&nV>-dTo; 495 } 496 if (isIn){ 497 return cast(T)(nV%to); 498 } else { 499 for (int i=0;i<1000;++i) { 500 nV=cast(int)source.next; 501 if (nV<dTo && nV>-dTo) break; 502 } 503 verify(nV<dTo && nV>-dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 504 return cast(T)(nV%to); 505 } 506 } else static if (is(T==long)){ 507 long d=long.max/to,dTo=to*d; 508 long nV=cast(long)source.nextL; 509 static if (excludeZero){ 510 int isIn=nV<dTo&&nV>-dTo&&nV!=0; 511 } else { 512 int isIn=nV<dTo&&nV>-dTo; 513 } 514 if (isIn){ 515 return nV%to; 516 } else { 517 for (int i=0;i<1000;++i) { 518 nV=source.nextL; 519 if (nV<dTo && nV>-dTo) break; 520 } 521 verify(nV<dTo && nV>-dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 522 return nV%to; 523 } 524 } else static if (is(T==float)||is(T==double)||is(T==real)){ 525 static if (T.mant_dig<30){ 526 static immutable T halfT=(cast(T)1)/(cast(T)2); 527 static immutable T fact32=ctfe_powI(halfT,32); 528 static immutable uint minV=1u<<T.mant_dig; 529 uint nV=source.next; 530 if (nV>=minV) { 531 T res=nV*fact32*to; 532 static if (boundCheck){ 533 if (res!=to) return (1-2*cast(int)(nV&1u))*res; 534 // to due to rounding (~3.e-8), 0 impossible with normal to values 535 verify(iter>0,"error with the generator, probability < 10^(-8*2000)"); 536 return uniformRSymm(to,iter-1); 537 } else { 538 return (1-2*cast(int)(nV&1u))*res; 539 } 540 } else { // probability 0.008 for 24 bit mantissa 541 T scale=fact32; 542 while (nV==0){ // probability 2.3283064365386963e-10 543 nV=source.next; 544 scale*=fact32; 545 } 546 uint nV2=source.next; 547 T res=(cast(T)nV+cast(T)nV2*fact32)*scale*to; 548 static if (excludeZero){ 549 if (res!=cast(T)0) return (1-2*cast(int)(nV&1u))*res; 550 verify(iter>0,"error with the generator, probability < 10^(-8*2000)"); 551 return uniformRSymm(to,iter-1); // 0 due to underflow (<1.e-38), 1 impossible 552 } else { 553 return (1-2*cast(int)(nV&1u))*res; 554 } 555 } 556 } else static if (T.mant_dig<62) { 557 static immutable T halfT=(cast(T)1)/(cast(T)2); 558 static immutable T fact64=ctfe_powI(halfT,64); 559 static immutable ulong minV=1UL<<(T.mant_dig); 560 ulong nV=source.nextL; 561 if (nV>=minV) { 562 T res=nV*fact64*to; 563 static if (boundCheck){ 564 if (res!=to) return (1-2*cast(int)(nV&1UL))*res; 565 // to due to rounding (<1.e-16), 0 impossible with normal to values 566 verify(iter>0,"error with the generator, probability < 10^(-16*2000)"); 567 return uniformRSymm(to,iter-1); 568 } else { 569 return (1-2*cast(int)(nV&1UL))*res; 570 } 571 } else { // probability 0.00048828125 for 53 bit mantissa 572 static immutable T fact32=ctfe_powI(halfT,32); 573 static immutable ulong minV2=1UL<<(T.mant_dig-32); 574 if (nV>=minV2){ 575 uint nV2=source.next; 576 T res=((cast(T)nV)+(cast(T)nV2)*fact32)*fact64*to; 577 return (1-2*cast(int)(nV2&1UL))*res; // cannot be 0 or to with normal to values 578 } else { // probability 1.1368683772161603e-13 for 53 bit mantissa 579 T scale=fact64; 580 while (nV==0){ 581 nV=source.nextL; 582 scale*=fact64; 583 } 584 ulong nV2=source.nextL; 585 T res=to*scale*((cast(T)nV)+(cast(T)nV2)*fact64); 586 static if (excludeZero){ 587 if (res!=cast(T)0) return (1-2*cast(int)(nV2&1UL))*res; 588 // 0 due to underflow (<1.e-307) 589 verify(iter>0,"error with the generator, probability < 10^(-16*2000)"); 590 return uniformRSymm(to,iter-1); 591 } else { 592 return (1-2*cast(int)(nV2&1UL))*res; 593 } 594 } 595 } 596 } else static if (T.mant_dig<=64) { 597 static immutable T halfT=(cast(T)1)/(cast(T)2); 598 static immutable T fact8=ctfe_powI(halfT,8); 599 static immutable T fact72=ctfe_powI(halfT,72); 600 ubyte nB=source.nextB; 601 if (nB!=0){ 602 ulong nL=source.nextL; 603 T res=to*(nB*fact8+nL*fact72); 604 static if (boundCheck){ 605 if (res!=to) return (1-2*cast(int)(nL&1UL))*res; 606 // 1 due to rounding (<1.e-16), 0 impossible with normal to values 607 verify(iter>0,"error with the generator, probability < 10^(-16*2000)"); 608 return uniformRSymm(to,iter-1); 609 } else { 610 return (1-2*cast(int)(nL&1UL))*res; 611 } 612 } else { // probability 0.00390625 613 static immutable T fact64=ctfe_powI(halfT,64); 614 T scale=fact8; 615 while (nB==0){ 616 nB=source.nextB; 617 scale*=fact8; 618 } 619 ulong nL=source.nextL; 620 T res=((cast(T)nB)+(cast(T)nL)*fact64)*scale*to; 621 static if (excludeZero){ 622 if (res!=cast(T)0) return ((nL&1UL)?res:-res); 623 // 0 due to underflow (<1.e-4932), 1 impossible 624 verify(iter>0,"error with the generator, probability < 10^(-16*2000)"); 625 return uniformRSymm(to,iter-1); 626 } else { 627 return ((nL&1UL)?res:-res); 628 } 629 } 630 } else { 631 // (T.mant_dig > 64 bits), not so optimized, but works for any size 632 static immutable T halfT=(cast(T)1)/(cast(T)2); 633 static immutable T fact32=ctfe_powI(halfT,32); 634 uint nL=source.next; 635 T fact=fact32; 636 while (nL==0){ 637 fact*=fact32; 638 nL=source.next; 639 } 640 T res=nL*fact; 641 for (int rBits=T.mant_dig;rBits>0;rBits-=32) { 642 fact*=fact32; 643 nL=source.next(); 644 res+=nL*fact; 645 } 646 static if (boundCheck){ 647 if (res!=to && res!=cast(T)0) return ((nL&1UL)?res:-res); 648 // 1 due to rounding (<1.e-16), 0 impossible with normal to values 649 verify(iter>0,"error with the generator, probability < 10^(-16*2000)"); 650 return uniformRSymm(to,iter-1); 651 } else { 652 return ((nL&1UL)?res:-res); 653 } 654 } 655 } else static assert(0,T.stringof~" unsupported type for uniformRSymm distribution"); 656 } 657 /// uniform distribution [from;to$(RPAREN) for integers, and (from;) for floating point numbers. 658 /// if boundCheck is false the bounds are included in the floating point number distribution. 659 /// the range for int and long is limited to only half the possible range 660 /// (it could be worked around using long aritmethic for int, and doing a carry by hand for long, 661 /// but I think it is seldomly needed, for int you are better off using long when needed) 662 T uniformR2(T,bool boundCheck=true)(T from,T to) 663 { 664 verify(to>from,"empy range in uniformR2"); 665 static if (is(T==int) || is(T==long)){ 666 verify(from>T.min/2&&to<T.max/2," from..to range too big"); 667 } 668 static if (is(T==int)||is(T==long)||is(T==uint)||is(T==ulong)){ 669 return from+uniformR(to-from); 670 } else static if (is(T==char) || is(T==byte) || is(T==ubyte) || is(T==short) || is(T==ushort)){ 671 int d=cast(int)to-cast(int)from; 672 int nV=uniformR!(int)(d); 673 return cast(T)(nV+cast(int)from); 674 } else static if (is(T==float) || is(T==double) || is(T==real)){ 675 T res=from+(to-from)*uniform!(T,false); 676 static if (boundCheck){ 677 if (res!=from && res!=to) return res; 678 return uniformR2(from,to); 679 } else { 680 return res; 681 } 682 } else static assert(0,T.stringof~" unsupported type for uniformR2 distribution"); 683 } 684 /// returns a random element of the given array (which must be non empty) 685 T uniformEl(T)(T[] arr){ 686 verify(arr.length>0,"array has to be non empty"); 687 return arr[uniformR(arr.length)]; 688 } 689 690 /************************************************************************** 691 692 Randomizes the given array and returns it (for some types this is 693 potentially more efficient, both from the use of random numbers 694 and speedwise) 695 696 *************************************************************************/ 697 698 U randomizeUniform(U,bool boundCheck)(ref U a){ 699 static if (is(U S:S[])){ 700 alias StripAllArrays!(U) T; 701 static if (is(T==byte)||is(T==ubyte)||is(T==char)){ 702 uint val=source.next; /// begin without value? 703 int rest=4; 704 for (size_t i=0;i<a.length;++i) { 705 if (rest!=0){ 706 a[i]=cast(T)(0xFFu&val); 707 val>>=8; 708 --rest; 709 } else { 710 val=source.next; 711 a[i]=cast(T)(0xFFu&val); 712 val>>=8; 713 rest=3; 714 } 715 } 716 } else static if (is(T==uint)||is(T==int)){ 717 T* aEnd=a.ptr+a.length; 718 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr) 719 *aPtr=cast(T)(source.next); 720 } else static if (is(T==ulong)||is(T==long)){ 721 T* aEnd=a.ptr+a.length; 722 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr) 723 *aPtr=cast(T)(source.nextL); 724 } else static if (is(T==float)|| is(T==double)|| is(T==real)) { 725 // optimize more? not so easy with guaranteed full mantissa initialization 726 T* aEnd=a.ptr+a.length; 727 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 728 *aPtr=uniform!(T,boundCheck)(); 729 } 730 } else static assert(T.stringof~" type not supported by randomizeUniform"); 731 } else { 732 a=uniform!(U,boundCheck)(); 733 } 734 return a; 735 } 736 737 /************************************************************************** 738 739 Randomizes the given array and returns it (for some types this is 740 potentially more efficient, both from the use of random numbers 741 and speedwise) 742 743 *************************************************************************/ 744 745 U randomizeUniformR(U,V,bool boundCheck=true)(ref U a,V to) 746 { 747 verify((cast(StripAllArrays!(U))to)>0,"empty range"); 748 alias StripAllArrays!(U) T; 749 static assert(is(V:T),"incompatible a and to type "~U.stringof~" "~V.stringof); 750 static if (is(U S:S[])){ 751 static if (is(T==uint) || is(T==int) || is(T==char) || is(T==byte) || is(T==ubyte)){ 752 uint d=uint.max/cast(uint)to,dTo=(cast(uint)to)*d; 753 T* aEnd=a.ptr+a.length; 754 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 755 uint nV=source.next; 756 if (nV<dTo){ 757 *aPtr=cast(T)(nV % cast(uint)to); 758 } else { 759 for (int i=0;i<1000;++i) { 760 nV=source.next; 761 if (nV<dTo) break; 762 } 763 verify(nV<dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 764 *aPtr=cast(T)(nV % cast(uint)to); 765 } 766 } 767 } else static if (is(T==ulong) || is(T==long)){ 768 ulong d=ulong.max/cast(ulong)to,dTo=(cast(ulong)to)*d; 769 T* aEnd=a.ptr+a.length; 770 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 771 ulong nV=source.nextL; 772 if (nV<dTo){ 773 el=cast(T)(nV % cast(ulong)to); 774 } else { 775 for (int i=0;i<1000;++i) { 776 nV=source.nextL; 777 if (nV<dTo) break; 778 } 779 verify(nV<dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 780 el=cast(T)(nV% cast(ulong)to); 781 } 782 } 783 } else static if (is(T==float) || is(T==double) || is(T==real)){ 784 T* aEnd=a.ptr+a.length; 785 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 786 *aPtr=uniformR!(T,boundCheck)(cast(T)to); 787 } 788 } else static assert(0,T.stringof~" unsupported type for uniformR distribution"); 789 } else { 790 a=uniformR!(T,boundCheck)(cast(T)to); 791 } 792 return a; 793 } 794 795 /************************************************************************** 796 797 Randomizes the given array and returns it (for some types this is 798 potentially more efficient, both from the use of random numbers 799 and speedwise) 800 801 *************************************************************************/ 802 803 U randomizeUniformR2(U,V,W,bool boundCheck=true)(ref U a,V from, W to) 804 { 805 alias StripAllArrays!(U) T; 806 verify((cast(T)to)>(cast(T)from),"empy range in uniformR2"); 807 static if (is(T==int) || is(T==long)){ 808 verify(from>T.min/2&&to<T.max/2," from..to range too big"); 809 } 810 alias StripAllArrays!(U) T; 811 static assert(is(V:T),"incompatible a and from type "~U.stringof~" "~V.stringof); 812 static assert(is(W:T),"incompatible a and to type "~U.stringof~" "~W.stringof); 813 static if (is(U S:S[])){ 814 static if (is(T==uint)||is(T==ulong)){ 815 T d=cast(T)to-cast(T)from; 816 T* aEnd=a.ptr+a.length; 817 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 818 *aPtr=from+uniformR!(d)(); 819 } 820 } else if (is(T==char) || is(T==byte) || is(T==ubyte)){ 821 int d=cast(int)to-cast(int)from; 822 T* aEnd=a.ptr+a.length; 823 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 824 *aPtr=cast(T)(uniformR!(d)+cast(int)from); 825 } 826 } else static if (is(T==float) || is(T==double) || is(T==real)){ 827 T* aEnd=a.ptr+a.length; 828 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 829 T res=cast(T)from+(cast(T)to-cast(T)from)*uniform!(T,false); 830 static if (boundCheck){ 831 if (res!=cast(T)from && res!=cast(T)to){ 832 *aPtr=res; 833 } else { 834 *aPtr=uniformR2!(T,boundCheck)(cast(T)from,cast(T)to); 835 } 836 } else { 837 *aPtr=res; 838 } 839 } 840 } else static assert(0,T.stringof~" unsupported type for uniformR2 distribution"); 841 } else { 842 a=uniformR2!(T,boundCheck)(from,to); 843 } 844 return a; 845 } 846 /// randomizes the given variable like uniformRSymm and returns it 847 /// (for some types this is potentially more efficient, both from the use of 848 /// random numbers and speedwise) 849 U randomizeUniformRSymm(U,V,bool boundCheck=true, bool 850 excludeZero=isFloat!(StripAllArrays!(U))) 851 (ref U a,V to) 852 { 853 alias StripAllArrays!(U) T; 854 verify((cast(T)to)>0,"empty range"); 855 static assert(is(V:T),"incompatible a and to type "~U.stringof~" "~V.stringof); 856 static if (is(U S:S[])){ 857 static if (is(T==int)|| is(T==byte)){ 858 int d=int.max/cast(int)to,dTo=(cast(int)to)*d; 859 T* aEnd=a.ptr+a.length; 860 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 861 int nV=cast(int)source.next; 862 static if (excludeZero){ 863 int isIn=nV<dTo&&nV>-dTo&&nV!=0; 864 } else { 865 int isIn=nV<dTo&&nV>-dTo; 866 } 867 if (isIn){ 868 *aPtr=cast(T)(nV% cast(int)to); 869 } else { 870 for (int i=0;i<1000;++i) { 871 nV=cast(int)source.next; 872 if (nV<dTo&&nV>-dTo) break; 873 } 874 verify(nV<dTo && nV>-dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 875 *aPtr=cast(T)(nV% cast(int)to); 876 } 877 } 878 } else static if (is(T==long)){ 879 long d=long.max/cast(T)to,dTo=(cast(T)to)*d; 880 long nV=cast(long)source.nextL; 881 T* aEnd=a.ptr+a.length; 882 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 883 static if (excludeZero){ 884 int isIn=nV<dTo&&nV>-dTo&&nV!=0; 885 } else { 886 int isIn=nV<dTo&&nV>-dTo; 887 } 888 if (isIn){ 889 *aPtr=nV% cast(T)to; 890 } else { 891 for (int i=0;i<1000;++i) { 892 nV=source.nextL; 893 if (nV<dTo && nV>-dTo) break; 894 } 895 verify(nV<dTo && nV>-dTo,"this is less probable than 1.e-301, something is wrong with the random number generator"); 896 *aPtr=nV% cast(T)to; 897 } 898 } 899 } else static if (is(T==float)||is(T==double)||is(T==real)){ 900 T* aEnd=a.ptr+a.length; 901 for (T* aPtr=a.ptr;aPtr!=aEnd;++aPtr){ 902 *aPtr=uniformRSymm!(T,boundCheck,excludeZero)(cast(T)to); 903 } 904 } else static assert(0,T.stringof~" unsupported type for uniformRSymm distribution"); 905 } else { 906 a=uniformRSymm!(T,boundCheck,excludeZero)(cast(T)to); 907 } 908 return a; 909 } 910 911 /// returns another (mostly indipendent, depending on seed size) random generator 912 RandG spawn(RandG=RandomG)(){ 913 RandG res=new RandG(false); 914 res.seed(&uniform!(uint)); 915 return res; 916 } 917 918 // ------- structs for uniform distributions ----- 919 /// uniform distribution on the whole range for integers, and on (0;1) for floats 920 /// with boundCheck=true this is equivalent to r itself, here just for completness 921 struct UniformDistribution(T,bool boundCheck){ 922 RandomG r; 923 static UniformDistribution create(RandomG r){ 924 UniformDistribution res; 925 res.r=r; 926 return res; 927 } 928 /// chainable call style initialization of variables (thorugh a call to randomize) 929 UniformDistribution opCall(U,S...)(ref U a,S args){ 930 randomize(a,args); 931 return this; 932 } 933 /// returns a random number 934 T getRandom(){ 935 return r.uniform!(T,boundCheck)(); 936 } 937 /// initialize el 938 U randomize(U)(ref U a){ 939 return r.randomizeUniform!(U,boundCheck)(a); 940 } 941 } 942 943 /// uniform distribution on the subrange [0;to$(RPAREN) for integers, (0;to) for floats 944 struct UniformRDistribution(T,bool boundCheck){ 945 T to; 946 RandomG r; 947 /// initializes the probability distribution 948 static UniformRDistribution create(RandomG r,T to){ 949 UniformRDistribution res; 950 res.r=r; 951 res.to=to; 952 return res; 953 } 954 /// chainable call style initialization of variables (thorugh a call to randomize) 955 UniformRDistribution opCall(U)(ref U a){ 956 randomize(a); 957 return this; 958 } 959 /// returns a random number 960 T getRandom(){ 961 return r.uniformR!(T,boundCheck)(to); 962 } 963 /// initialize el 964 U randomize(U)(ref U a){ 965 return r.randomizeUniformR!(U,T,boundCheck)(a,to); 966 } 967 } 968 969 /// uniform distribution on the subrange (-to;to) for integers, (-to;0)u(0;to) for floats 970 /// excludeZero controls if the zero should be excluded, boundCheck if the boundary should 971 /// be excluded for floats 972 struct UniformRSymmDistribution(T,bool boundCheck=true,bool excludeZero=isFloat!(T)){ 973 T to; 974 RandomG r; 975 /// initializes the probability distribution 976 static UniformRSymmDistribution create(RandomG r,T to){ 977 UniformRSymmDistribution res; 978 res.r=r; 979 res.to=to; 980 return res; 981 } 982 /// chainable call style initialization of variables (thorugh a call to randomize) 983 UniformRSymmDistribution opCall(U)(ref U a){ 984 randomize(a); 985 return this; 986 } 987 /// returns a random number 988 T getRandom(){ 989 return r.uniformRSymm!(T,boundCheck,excludeZero)(to); 990 } 991 /// initialize el 992 U randomize(U)(ref U a){ 993 return r.randomizeUniformRSymm!(U,T,boundCheck)(a,to); 994 } 995 } 996 997 /// uniform distribution on the subrange (-to;to) for integers, (0;to) for floats 998 struct UniformR2Distribution(T,bool boundCheck){ 999 T from,to; 1000 RandomG r; 1001 /// initializes the probability distribution 1002 static UniformR2Distribution create(RandomG r,T from, T to){ 1003 UniformR2Distribution res; 1004 res.r=r; 1005 res.from=from; 1006 res.to=to; 1007 return res; 1008 } 1009 /// chainable call style initialization of variables (thorugh a call to randomize) 1010 UniformR2Distribution opCall(U,S...)(ref U a,S args){ 1011 randomize(a,args); 1012 return this; 1013 } 1014 /// returns a random number 1015 T getRandom(){ 1016 return r.uniformR2!(T,boundCheck)(from,to); 1017 } 1018 /// initialize a 1019 U randomize(U)(ref U a){ 1020 return r.randomizeUniformR2!(U,T,T,boundCheck)(a,from,to); 1021 } 1022 } 1023 1024 // ---------- gamma distribution, move to a separate module? -------- 1025 /// gamma distribution f=x^(alpha-1)*exp(-x/theta)/(gamma(alpha)*theta^alpha) 1026 /// alpha has to be bigger than 1, for alpha<1 use gammaD(alpha)=gammaD(alpha+1)*pow(r.uniform!(T),1/alpha) 1027 /// from Marsaglia and Tsang, ACM Transaction on Mathematical Software, Vol. 26, N. 3 1028 /// 2000, p 363-372 1029 struct GammaDistribution(T){ 1030 RandomG r; 1031 T alpha; 1032 T theta; 1033 static GammaDistribution create(RandomG r,T alpha=cast(T)1,T theta=cast(T)1){ 1034 GammaDistribution res; 1035 res.r=r; 1036 res.alpha=alpha; 1037 res.theta=theta; 1038 verify(alpha>=cast(T)1,"implemented only for alpha>=1"); 1039 return res; 1040 } 1041 /// chainable call style initialization of variables (thorugh a call to randomize) 1042 GammaDistribution opCall(U,S...)(ref U a,S args){ 1043 randomize(a,args); 1044 return this; 1045 } 1046 /// returns a single random number 1047 T getRandom(T a=alpha,T t=theta) 1048 { 1049 verify(a>=cast(T)1,"implemented only for alpha>=1"); 1050 T d=a-(cast(T)1)/(cast(T)3); 1051 T c=(cast(T)1)/sqrt(d*cast(T)9); 1052 auto n=r.normalSource!(T)(); 1053 for (;;) { 1054 do { 1055 T x=n.getRandom(); 1056 T v=c*x+cast(T)1; 1057 v=v*v*v; // might underflow (in extreme situations) so it is in the loop 1058 } while (v<=0); 1059 T u=r.uniform!(T)(); 1060 if (u<1-(cast(T)0.331)*(x*x)*(x*x)) return t*d*v; 1061 if (log(u)< x*x/2+d*(1-v+log(v))) return t*d*v; 1062 } 1063 } 1064 /// initializes b with gamma distribued random numbers 1065 U randomize(U)(ref U b,T a=alpha,T t=theta){ 1066 static if (is(U S:S[])) { 1067 alias StripAllArrays!(U) T; 1068 T* bEnd=b.ptr+b.length; 1069 for (T* bPtr=b.ptr;bPtr!=bEnd;++bPtr){ 1070 *bPtr=cast(StripAllArrays!(U)) getRandom(a,t); 1071 } 1072 } else { 1073 b=cast(U) getRandom(a,t); 1074 } 1075 return b; 1076 } 1077 /// maps op on random numbers (of type T) and initializes b with it 1078 U randomizeOp(U,S)(scope S delegate(T)op, ref U b,T a=alpha, T t=theta){ 1079 static if(is(U S:S[])){ 1080 alias StripAllArrays!(U) T; 1081 T* bEnd=b.ptr+b.length; 1082 for (T* bPtr=b.ptr;bPtr!=bEnd;++bPtr){ 1083 *bPtr=cast(StripAllArrays!(U))op(getRandom(a,t)); 1084 } 1085 } else { 1086 b=cast(U)op(getRandom(a)); 1087 } 1088 return b; 1089 } 1090 } 1091 1092 //-------- various distributions available ----------- 1093 1094 /// generators of normal numbers (sigma=1,mu=0) of the given type 1095 /// f=exp(-x*x/(2*sigma^2))/(sqrt(2 pi)*sigma) 1096 NormalSource!(RandomG,T) normalSource(T)(){ 1097 static if(is(T==float)){ 1098 if (!normalFloat) normalFloat=new NormalSource!(RandomG,T)(this); 1099 return normalFloat; 1100 } else static if (is(T==double)){ 1101 if (!normalDouble) normalDouble=new NormalSource!(RandomG,T)(this); 1102 return normalDouble; 1103 } else static if (is(T==real)){ 1104 if (!normalReal) normalReal=new NormalSource!(RandomG,T)(this); 1105 return normalReal; 1106 } else static assert(0,T.stringof~" no normal source implemented"); 1107 } 1108 1109 /// generators of exp distribued numbers (beta=1) of the given type 1110 /// f=1/beta*exp(-x/beta) 1111 ExpSource!(RandomG,T) expSource(T)(){ 1112 static if(is(T==float)){ 1113 if (!expFloat) expFloat=new ExpSource!(RandomG,T)(this); 1114 return expFloat; 1115 } else static if (is(T==double)){ 1116 if (!expDouble) expDouble=new ExpSource!(RandomG,T)(this); 1117 return expDouble; 1118 } else static if (is(T==real)){ 1119 if (!expReal) expReal=new ExpSource!(RandomG,T)(this); 1120 return expReal; 1121 } else static assert(0,T.stringof~" no exp source implemented"); 1122 } 1123 1124 /// generators of normal numbers with a different default sigma/mu 1125 /// f=exp(-x*x/(2*sigma^2))/(sqrt(2 pi)*sigma) 1126 NormalSource!(RandomG,T).NormalDistribution normalD(T)(T sigma=cast(T)1,T mu=cast(T)0){ 1127 return normalSource!(T).normalD(sigma,mu); 1128 } 1129 /// exponential distribued numbers with a different default beta 1130 /// f=1/beta*exp(-x/beta) 1131 ExpSource!(RandomG,T).ExpDistribution expD(T)(T beta){ 1132 return expSource!(T).expD(beta); 1133 } 1134 /// gamma distribued numbers with the given default alpha 1135 GammaDistribution!(T) gammaD(T)(T alpha=cast(T)1,T theta=cast(T)1){ 1136 return GammaDistribution!(T).create(this,alpha,theta); 1137 } 1138 1139 /// uniform distribution on the whole integer range, and on (0;1) for floats 1140 /// should return simply this?? 1141 UniformDistribution!(T,true) uniformD(T)(){ 1142 return UniformDistribution!(T,true).create(this); 1143 } 1144 /// uniform distribution on the whole integer range, and on [0;1] for floats 1145 UniformDistribution!(T,false) uniformBoundsD(T)(){ 1146 return UniformDistribution!(T,false).create(this); 1147 } 1148 /// uniform distribution [0;to$(RPAREN) for ints, (0:to) for reals 1149 UniformRDistribution!(T,true) uniformRD(T)(T to){ 1150 return UniformRDistribution!(T,true).create(this,to); 1151 } 1152 /// uniform distribution [0;to$(RPAREN) for ints, [0:to] for reals 1153 UniformRDistribution!(T,false) uniformRBoundsD(T)(T to){ 1154 return UniformRDistribution!(T,false).create(this,to); 1155 } 1156 /// uniform distribution (-to;to) for ints and (-to;0)u(0;to) for reals 1157 UniformRSymmDistribution!(T,true,isFloat!(T)) uniformRSymmD(T)(T to){ 1158 return UniformRSymmDistribution!(T,true,isFloat!(T)).create(this,to); 1159 } 1160 /// uniform distribution (-to;to) for ints and [-to;0$(RPAREN)u$(LPAREN)0;to] for reals 1161 UniformRSymmDistribution!(T,false,isFloat!(T)) uniformRSymmBoundsD(T)(T to){ 1162 return UniformRSymmDistribution!(T,false,isFloat!(T)).create(this,to); 1163 } 1164 /// uniform distribution [from;to$(RPAREN) for ints and (from;to) for reals 1165 UniformR2Distribution!(T,true) uniformR2D(T)(T from, T to){ 1166 return UniformR2Distribution!(T,true).create(this,from,to); 1167 } 1168 /// uniform distribution [from;to$(RPAREN) for ints and [from;to] for reals 1169 UniformR2Distribution!(T,false) uniformR2BoundsD(T)(T from, T to){ 1170 return UniformR2Distribution!(T,false).create(this,from,to); 1171 } 1172 1173 // -------- Utility functions for other distributions ------- 1174 // add also the corresponding randomize functions? 1175 1176 /// returns a normal distribued number 1177 T normal(T)(){ 1178 return normalSource!(T).getRandom(); 1179 } 1180 /// returns a normal distribued number with the given sigma 1181 T normalSigma(T)(T sigma){ 1182 return normalSource!(T).getRandom(sigma); 1183 } 1184 /// returns a normal distribued number with the given sigma and mu 1185 T normalSigmaMu(T)(T sigma,T mu){ 1186 return normalSource!(T).getRandom(sigma,mu); 1187 } 1188 1189 /// returns an exp distribued number 1190 T exp(T)(){ 1191 return expSource!(T).getRandom(); 1192 } 1193 /// returns an exp distribued number with the given scale beta 1194 T expBeta(T)(T beta){ 1195 return expSource!(T).getRandom(beta); 1196 } 1197 1198 /// returns a gamma distribued number 1199 /// from Marsaglia and Tsang, ACM Transaction on Mathematical Software, Vol. 26, N. 3 1200 /// 2000, p 363-372 1201 T gamma(T)(T alpha=cast(T)1,T sigma=cast(T)1) 1202 { 1203 verify(alpha>=cast(T)1,"implemented only for alpha>=1"); 1204 auto n=normalSource!(T); 1205 T d=alpha-(cast(T)1)/(cast(T)3); 1206 T c=(cast(T)1)/sqrt(d*cast(T)9); 1207 for (;;) { 1208 T x,v; 1209 do { 1210 x=n.getRandom(); 1211 v=c*x+cast(T)1; 1212 v=v*v*v; // might underflow (in extreme situations) so it is in the loop 1213 } while (v<=0); 1214 T u=uniform!(T)(); 1215 if (u<1-(cast(T)0.331)*(x*x)*(x*x)) return sigma*d*v; 1216 if (log(u)< x*x/2+d*(1-v+log(v))) return sigma*d*v; 1217 } 1218 } 1219 // --------------- 1220 1221 /// writes the current status in a string 1222 override istring toString(){ 1223 return source.toString(); 1224 } 1225 /// reads the current status from a string (that should have been trimmed) 1226 /// returns the number of chars read 1227 size_t fromString(cstring s){ 1228 return source.fromString(s); 1229 } 1230 1231 // make this by default a uniformRandom number generator 1232 /// chainable call style initialization of variables (thorugh a call to randomize) 1233 RandomG opCall(U)(ref U a){ 1234 randomize(a); 1235 return this; 1236 } 1237 /// returns a random number 1238 T getRandom(T)(){ 1239 return uniform!(T,true)(); 1240 } 1241 /// initialize el 1242 U randomize(U)(ref U a){ 1243 return randomizeUniform!(U,true)(a); 1244 } 1245 1246 } // end class RandomG 1247 1248 /// make the default random number generator type 1249 /// (a non threadsafe random number generator) easily available 1250 /// you can safely expect a new instance of this to be indipendent from all the others 1251 alias RandomG!() Random; 1252 /// default threadsafe random number generator type 1253 alias RandomG!(DefaultEngine) RandomSync; 1254 1255 /// shared locked (threadsafe) random number generator 1256 /// initialized with urandom if available, with time otherwise 1257 static RandomSync rand; 1258 static this () 1259 { 1260 rand = new RandomSync(false); 1261 1262 static void set_array_source(ulong s) 1263 { 1264 uint[2] a; 1265 a[0]= cast(uint)(s & 0xFFFF_FFFFUL); 1266 a[1]= cast(uint)(s>>32); 1267 rand.seed(&(ArraySource(a).next)); 1268 } 1269 1270 version (unittest){ 1271 set_array_source(9); // http://dilbert.com/strip/2001-10-25 1272 } else { 1273 URandom r; 1274 rand.seed(&r.next); 1275 } 1276 } 1277 1278 version (unittest) 1279 { 1280 import ocean.math.random.engines.KISS; 1281 import ocean.math.random.engines.CMWC; 1282 import core.stdc.stdio:printf; 1283 import ocean.core.Test; 1284 1285 /// very simple statistal test, mean within maxOffset, and maximum/minimum at least minmax/maxmin 1286 bool checkMean(T)(T[] a, real maxmin, real minmax, real expectedMean, real maxOffset,bool alwaysPrint=false,bool checkB=false){ 1287 T minV,maxV; 1288 real meanV=0.0L; 1289 if (a.length>0){ 1290 minV=a[0]; 1291 maxV=a[0]; 1292 foreach (el;a){ 1293 test(!checkB || (cast(T)0<el && el<cast(T)1),"el out of bounds"); 1294 if (el<minV) minV=el; 1295 if (el>maxV) maxV=el; 1296 meanV+=cast(real)el; 1297 } 1298 meanV/=cast(real)a.length; 1299 bool printM=false; 1300 if (cast(real)minV>maxmin) printM=true; 1301 if (cast(real)maxV<minmax) printM=true; 1302 if (expectedMean-maxOffset>meanV || meanV>expectedMean+maxOffset) printM=true; 1303 if (printM){ 1304 printf("WARNING ocean.math.Random statistic is strange: %.*s[%d] %Lg %Lg %Lg\n\0", 1305 cast(int)T.stringof.length, T.stringof.ptr, cast(int)a.length, 1306 cast(real)minV,meanV,cast(real)maxV); 1307 } else if (alwaysPrint) { 1308 printf("ocean.math.Random statistic: %.*s[%d] %Lg %Lg %Lg\n\0", 1309 cast(int)T.stringof.length, T.stringof.ptr, cast(int)a.length, 1310 cast(real)minV,meanV,cast(real)maxV); 1311 } 1312 return printM; 1313 } 1314 return false; 1315 } 1316 1317 /// check a given generator both on the whole array, and on each element separately 1318 bool doTests(RandG,Arrays...)(RandG r,real maxmin, real minmax, real expectedMean, real maxOffset,bool alwaysPrint,bool checkB, Arrays arrs){ 1319 bool gFail=false; 1320 foreach (i,TA;Arrays){ 1321 alias StripAllArrays!(TA) T; 1322 // all together 1323 r(arrs[i]); 1324 bool fail=checkMean!(T)(arrs[i],maxmin,minmax,expectedMean,maxOffset,alwaysPrint,checkB); 1325 // one by one 1326 foreach (ref el;arrs[i]){ 1327 r(el); 1328 } 1329 fail |= checkMean!(T)(arrs[i],maxmin,minmax,expectedMean,maxOffset,alwaysPrint,checkB); 1330 gFail |= fail; 1331 } 1332 return gFail; 1333 } 1334 1335 void testRandSource(RandS)(){ 1336 auto r=new RandomG!(RandS)(); 1337 // r.fromString("KISS99_b66dda10_49340130_8f3bf553_224b7afa_00000000_00000000"); // to reproduce a given test... 1338 auto initialState=r.toString(); // so that you can reproduce things... 1339 bool allStats=false; // set this to true to show all statistics (helpful to track an error) 1340 try{ 1341 r.uniform!(uint); 1342 r.uniform!(ubyte); 1343 r.uniform!(ulong); 1344 int count=10_000; 1345 for (int i=count;i!=0;--i){ 1346 float f=r.uniform!(float); 1347 test(0<f && f<1,"float out of bounds"); 1348 double d=r.uniform!(double); 1349 test(0<d && d<1,"double out of bounds"); 1350 real rr=r.uniform!(real); 1351 test(0<rr && rr<1,"double out of bounds"); 1352 } 1353 // checkpoint status (str) 1354 auto status=r.toString(); 1355 uint tVal=r.uniform!(uint); 1356 ubyte t2Val=r.uniform!(ubyte); 1357 ulong t3Val=r.uniform!(ulong); 1358 1359 byte[1000] barr; 1360 ubyte[1000] ubarr; 1361 uint[1000] uiarr; 1362 int[1000] iarr; 1363 float[1000] farr; 1364 double[1000]darr; 1365 real[1000] rarr; 1366 byte[] barr2=barr[]; 1367 ubyte[] ubarr2=ubarr[]; 1368 uint[] uiarr2=uiarr[]; 1369 int[] iarr2=iarr[]; 1370 float[] farr2=farr[]; 1371 double[]darr2=darr[]; 1372 real[] rarr2=rarr[]; 1373 1374 bool fail=false,gFail=false; 1375 fail =doTests(r,-100.0L,100.0L,0.0L,20.0L,allStats,false,barr2); 1376 fail|=doTests(r,100.0L,155.0L,127.5L,20.0L,allStats,false,ubarr2); 1377 fail|=doTests(r,0.25L*cast(real)(uint.max),0.75L*cast(real)uint.max, 1378 0.5L*uint.max,0.2L*uint.max,allStats,false,uiarr2); 1379 fail|=doTests(r,0.5L*cast(real)int.min,0.5L*cast(real)int.max, 1380 0.0L,0.2L*uint.max,allStats,false,iarr2); 1381 fail|=doTests(r,0.2L,0.8L,0.5L,0.2L,allStats,true,farr2,darr2,rarr2); 1382 gFail|=fail; 1383 1384 fail =doTests(r.uniformD!(int)(),-100.0L,100.0L,0.0L,20.0L,allStats,false,barr2); 1385 fail|=doTests(r.uniformD!(int)(),100.0L,155.0L,127.5L,20.0L,allStats,false,ubarr2); 1386 fail|=doTests(r.uniformD!(int)(),0.25L*cast(real)(uint.max),0.75L*cast(real)uint.max, 1387 0.5L*uint.max,0.2L*uint.max,allStats,false,uiarr2); 1388 fail|=doTests(r.uniformD!(real)(),0.5L*cast(real)int.min,0.5L*cast(real)int.max, 1389 0.0L,0.2L*uint.max,allStats,false,iarr2); 1390 fail|=doTests(r.uniformD!(real)(),0.2L,0.8L,0.5L,0.2L,allStats,true,farr2,darr2,rarr2); 1391 gFail|=fail; 1392 1393 fail =doTests(r.uniformBoundsD!(int)(),-100.0L,100.0L,0.0L,20.0L,allStats,false,barr2); 1394 fail|=doTests(r.uniformBoundsD!(int)(),100.0L,155.0L,127.5L,20.0L,allStats,false,ubarr2); 1395 fail|=doTests(r.uniformBoundsD!(int)(),0.25L*cast(real)(uint.max),0.75L*cast(real)uint.max, 1396 0.5L*uint.max,0.2L*uint.max,allStats,false,uiarr2); 1397 fail|=doTests(r.uniformBoundsD!(int)(),0.5L*cast(real)int.min,0.5L*cast(real)int.max, 1398 0.0L,0.2L*uint.max,allStats,false,iarr2); 1399 fail|=doTests(r.uniformBoundsD!(int)(),0.2L,0.8L,0.5L,0.2L,allStats,false,farr2,darr2,rarr2); 1400 gFail|=fail; 1401 1402 fail =doTests(r.uniformRD(cast(byte)101),25.0L,75.0L,50.0L,15.0L,allStats,false,barr2); 1403 fail|=doTests(r.uniformRD(cast(ubyte)201),50.0L,150.0L,100.0L,20.0L,allStats,false,ubarr2); 1404 fail|=doTests(r.uniformRD(1001u),250.0L,750.0L,500.0L,100.0L,allStats,false,uiarr2); 1405 fail|=doTests(r.uniformRD(1001 ),250.0L,750.0L,500.0L,100.0L,allStats,false,iarr2); 1406 fail|=doTests(r.uniformRD(1000.0L),250.0L,750.0L,500.0L,100.0L, 1407 allStats,false,farr2,darr2,rarr2); 1408 fail|=doTests(r.uniformRD(1.0L),0.2L,0.8L,0.5L,0.2L,allStats,true,farr2,darr2,rarr2); 1409 gFail|=fail; 1410 1411 fail =doTests(r.uniformRBoundsD(cast(byte)101),25.0L,75.0L,50.0L,15.0L,allStats,false,barr2); 1412 fail|=doTests(r.uniformRBoundsD(cast(ubyte)201),50.0L,150.0L,100.0L,20.0L,allStats,false,ubarr2); 1413 fail|=doTests(r.uniformRBoundsD(1001u),250.0L,750.0L,500.0L,100.0L,allStats,false,uiarr2); 1414 fail|=doTests(r.uniformRBoundsD(1001 ),250.0L,750.0L,500.0L,100.0L,allStats,false,iarr2); 1415 fail|=doTests(r.uniformRBoundsD(1000.0L),250.0L,750.0L,500.0L,100.0L, 1416 allStats,false,farr2,darr2,rarr2); 1417 gFail|=fail; 1418 1419 fail =doTests(r.uniformRSymmD!(byte)(cast(byte)100), 1420 -40.0L,40.0L,0.0L,30.0L,allStats,false,barr2); 1421 fail|=doTests(r.uniformRSymmD!(int)(1000), 1422 -300.0L,300.0L,0.0L,200.0L,allStats,false,iarr2); 1423 fail|=doTests(r.uniformRSymmD!(real)(1.0L), 1424 -0.3L,0.3L,0.0L,0.3L,allStats,false,farr2,darr2,rarr2); 1425 gFail|=fail; 1426 1427 fail =doTests(r.uniformRSymmBoundsD!(byte)(cast(byte)100), 1428 -40.0L,40.0L,0.0L,30.0L,allStats,false,barr2); 1429 fail|=doTests(r.uniformRSymmBoundsD!(int)(1000), 1430 -300.0L,300.0L,0.0L,200.0L,allStats,false,iarr2); 1431 fail|=doTests(r.uniformRSymmBoundsD!(real)(1.0L), 1432 -0.3L,0.3L,0.0L,0.3L,allStats,false,farr2,darr2,rarr2); 1433 gFail|=fail; 1434 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 1445 fail =doTests(r.expSource!(float)(),0.8L,2.0L,1.0L,1.0L, 1446 allStats,false,farr2,darr2,rarr2); 1447 fail|=doTests(r.expSource!(double)(),0.8L,2.0L,1.0L,1.0L, 1448 allStats,false,farr2,darr2,rarr2); 1449 fail|=doTests(r.expSource!(real)(),0.8L,2.0L,1.0L,1.0L, 1450 allStats,false,farr2,darr2,rarr2); 1451 fail|=doTests(r.expD!(real)(5.0L),1.0L,7.0L,5.0L,1.0L, 1452 allStats,false,farr2,darr2,rarr2); 1453 gFail|=fail; 1454 1455 uint seed = 0; 1456 r.seed({ return 2*(seed++); }); 1457 auto v1 = r.uniform!(int)(); 1458 1459 seed = 0; 1460 r.seed({ return 2*(seed++); }); 1461 auto v2 = r.uniform!(int)(); 1462 1463 test!("==")(v1, v2, "Re-seed failure: " ~ RandS.stringof); 1464 1465 r.fromString(status); 1466 test!("==")(r.uniform!(uint),tVal,"restoring of status from str failed"); 1467 test!("==")(r.uniform!(ubyte),t2Val,"restoring of status from str failed"); 1468 test!("==")(r.uniform!(ulong),t3Val,"restoring of status from str failed"); 1469 test(!gFail,"Random.d failure"); 1470 } catch(Exception e) { 1471 throw e; 1472 } 1473 } 1474 } 1475 1476 unittest { 1477 testRandSource!(Kiss99)(); 1478 testRandSource!(CMWC_default)(); 1479 testRandSource!(KissCmwc_default)(); 1480 testRandSource!(Twister)(); 1481 testRandSource!(DefaultEngine)(); 1482 }