1 // Written in the D programming language. 2 3 /** 4 * Implements algorithms for generating random numbers drawn from 5 * different statistical distributions. Where possible, each random 6 * _distribution is provided in two different forms: 7 * 8 * $(UL 9 * $(LI as a function, which takes as input the _distribution 10 * parameters and a uniform RNG, and returns a single value 11 * drawn from the distribution, and) 12 * $(LI as a range object, which wraps a uniform RNG instance and 13 * transforms its output into numbers drawn from the specified 14 * _distribution.) 15 * ) 16 * 17 * Typical reasons for rejecting a function implementation include 18 * the function needing to hold state between calls to achieve 19 * adequate performance, or the function needing to allocate memory 20 * with each call. 21 * 22 * As with random number generators, the random _distribution range 23 * objects implemented here are final classes in order to ensure 24 * reference semantics. They also assume reference type semantics on 25 * the part of the RNGs that they wrap: user-supplied value-type RNGs 26 * may produce unexpected and incorrect behaviour when combined with 27 * these objects. 28 * 29 * Note: $(D hap._random._distribution.dice) uses a different algorithm 30 * to its $(D std.random) counterpart and so will produce different 31 * results. 32 * 33 * Copyright: © 2008-2011 Andrei Alexandrescu, 34 * 2013 Chris Cain, 35 * 2013 Andrej Mitrović, 36 * 2013-2014 Joseph Rushton Wakeling 37 * 38 * License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 39 * 40 * Authors: $(WEB erdani.org, Andrei Alexandrescu), 41 * Chris Cain (discrete _distribution and integral-based uniform), 42 * Andrej Mitrović (enum-based uniform), 43 * $(WEB braingam.es, Joseph Rushton Wakeling) 44 * 45 * Source: $(HAPSRC hap/random/_distribution.d) 46 */ 47 module hap.random.distribution; 48 49 import hap.random.generator, hap.random.traits; 50 51 import std.range, std.traits; 52 53 // dice 54 /** 55 * Rolls a random die with relative probabilities stored in $(D proportions). 56 * Returns the index in $(D proportions) that was chosen. 57 * 58 * Example: 59 * ---- 60 * auto x = dice(0.5, 0.5); // x is 0 or 1 in equal proportions 61 * auto y = dice(50, 50); // y is 0 or 1 in equal proportions 62 * auto z = dice(70, 20, 10); // z is 0 70% of the time, 1 20% of the time, 63 * // and 2 10% of the time 64 * ---- 65 * 66 * The range counterpart of $(D dice) is the $(D DiscreteDistribution) class. 67 * 68 * Note: given an identically-seeded RNG as input, $(D hap.random.distribution._dice) 69 * will produce different values to $(D std.random._dice). 70 */ 71 size_t dice(UniformRNG, Num)(UniformRNG rng, Num[] proportions...) 72 if (isNumeric!Num && isForwardRange!UniformRNG) 73 { 74 return diceImpl(rng, proportions); 75 } 76 77 /// ditto 78 size_t dice(UniformRNG, Range)(UniformRNG rng, Range proportions) 79 if (isUniformRNG!UniformRNG && isForwardRange!Range && 80 isNumeric!(ElementType!Range) && !isArray!Range) 81 { 82 return diceImpl(rng, proportions); 83 } 84 85 /// ditto 86 size_t dice(Range)(Range proportions) 87 if (isForwardRange!Range && isNumeric!(ElementType!Range) && !isArray!Range) 88 { 89 return diceImpl(rndGen, proportions); 90 } 91 92 /// ditto 93 size_t dice(Num)(Num[] proportions...) 94 if (isNumeric!Num) 95 { 96 return diceImpl(rndGen, proportions); 97 } 98 99 private size_t diceImpl(UniformRNG, Range)(UniformRNG rng, Range proportions) 100 if (isUniformRNG!UniformRNG && isForwardRange!Range && isNumeric!(ElementType!Range)) 101 { 102 import std.algorithm, std.exception, hap.random.distribution; 103 104 alias T = DiceType!Range; 105 106 T sum = reduce!((a, b) { assert(b >= 0); return a + b; })(cast(T) 0, proportions.save); 107 enforce(sum > 0, "Proportions in a dice cannot sum to zero"); 108 109 immutable point = uniform!("[)", T, T)(0, sum, rng); 110 assert(point < sum); 111 T mass = 0; 112 113 size_t i = 0; 114 foreach (e; proportions) 115 { 116 mass += e; 117 if (point < mass) 118 { 119 return i; 120 } 121 i++; 122 } 123 // this point should not be reached 124 assert(false); 125 } 126 127 unittest 128 { 129 foreach (UniformRNG; UniformRNGTypes) 130 { 131 auto rng = new UniformRNG(unpredictableSeed); 132 133 foreach (immutable _; 0 .. 100) 134 { 135 auto i = dice(rng, 0.0, 100.0); 136 assert(i == 1); 137 138 i = dice(rng, 100.0, 0.0); 139 assert(i == 0); 140 141 i = dice(100U, 0U); 142 assert(i == 0); 143 } 144 145 import std.typetuple; 146 147 foreach(T; TypeTuple!(byte, ubyte, short, ushort, int, uint, 148 long, ulong, float, double, real)) 149 { 150 foreach (immutable l; 2 .. 100) 151 { 152 auto prop = new T[l]; 153 prop[] = 0; 154 prop[0] = 10; 155 prop[$-1] = 10; 156 157 foreach (immutable _; 0 .. 100) 158 { 159 auto i = dice(rng, prop); 160 assert(i == 0 || i == l - 1); 161 } 162 } 163 } 164 } 165 } 166 167 package template DiceType(Range) 168 if (isInputRange!Range && isNumeric!(ElementType!Range)) 169 { 170 alias DiceType = DiceType!(ElementType!Range); 171 } 172 173 package template DiceType(T) 174 if (isNumeric!T) 175 { 176 static if (isIntegral!T) 177 { 178 static if (is(Largest!(ushort, Unsigned!T) == ushort)) 179 { 180 alias DiceType = uint; 181 } 182 else static if (is(Largest!(ulong, Unsigned!T) == ulong)) 183 { 184 alias DiceType = ulong; 185 } 186 else 187 { 188 static assert(false); 189 } 190 } 191 else static if (isFloatingPoint!T) 192 { 193 alias DiceType = Largest!(double, T); 194 } 195 } 196 197 unittest 198 { 199 static assert(is(DiceType!byte == uint)); 200 static assert(is(DiceType!ubyte == uint)); 201 static assert(is(DiceType!short == uint)); 202 static assert(is(DiceType!ushort == uint)); 203 static assert(is(DiceType!int == ulong)); 204 static assert(is(DiceType!uint == ulong)); 205 static assert(is(DiceType!float == double)); 206 static assert(is(DiceType!double == double)); 207 static assert(is(DiceType!real == real)); 208 209 static assert(is(DiceType!(byte[]) == uint)); 210 static assert(is(DiceType!(ubyte[]) == uint)); 211 static assert(is(DiceType!(short[]) == uint)); 212 static assert(is(DiceType!(ushort[]) == uint)); 213 static assert(is(DiceType!(int[]) == ulong)); 214 static assert(is(DiceType!(uint[]) == ulong)); 215 static assert(is(DiceType!(float[]) == double)); 216 static assert(is(DiceType!(double[]) == double)); 217 static assert(is(DiceType!(real[]) == real)); 218 } 219 220 /** 221 * The range equivalent of $(D dice), each element of which is the 222 * result of the roll of a random die with relative probabilities 223 * stored in the range $(D proportions). Each successive value of 224 * $(D front) reflects the index in $(D proportions) that was chosen. 225 * If no random number generator is specified, the default $(D rndGen) 226 * will be used as the source of randomness. 227 * 228 * This offers a superior option in the event of making many rolls 229 * of the same die, as the sum and CDF of $(D proportions) only needs 230 * to be calculated upon construction and not with each call. 231 */ 232 final class DiscreteDistribution(SearchPolicy search, T, UniformRNG) 233 { 234 private: 235 SortedRange!(immutable(T)[]) _cumulativeProportions; 236 UniformRNG _rng; 237 size_t _value; 238 239 public: 240 enum bool isRandomDistribution = true; 241 242 this(Range)(UniformRNG rng, Range proportions) 243 if (isInputRange!Range && isNumeric!(ElementType!Range)) 244 in 245 { 246 assert(!proportions.empty, "Proportions of discrete distribution cannot be empty."); 247 } 248 body 249 { 250 import std.exception; 251 252 _rng = rng; 253 254 static if (isImplicitlyConvertible!(typeof(proportions.array), T[])) 255 { 256 T[] prop = proportions.array; 257 } 258 else 259 { 260 import std.algorithm, std.conv; 261 T[] prop = proportions.map!(to!T).array; 262 } 263 264 alias A = Select!(isFloatingPoint!T, real, T); 265 266 A accumulator = 0; 267 268 foreach(ref e; prop) 269 { 270 assert(e >= 0, "Proportions of discrete distribution cannot be negative."); 271 272 debug 273 { 274 A preAccumulation = accumulator; 275 } 276 277 accumulator += e; 278 279 debug 280 { 281 static if (isIntegral!T) 282 { 283 enforce(preAccumulation <= accumulator, "Integer overflow detected!"); 284 } 285 else static if (isFloatingPoint!T) 286 { 287 if (e > 0) 288 { 289 enforce(accumulator > preAccumulation, "Floating point rounding error detected!"); 290 } 291 } 292 else 293 { 294 static assert(0); 295 } 296 } 297 298 e = accumulator; 299 } 300 301 _cumulativeProportions = assumeSorted(assumeUnique(prop)[]); 302 303 popFront(); 304 } 305 306 this(typeof(this) that) 307 { 308 this._cumulativeProportions = that._cumulativeProportions.save; 309 this._rng = that._rng; 310 this._value = that._value; 311 } 312 313 /// Range primitives 314 enum bool empty = false; 315 316 /// ditto 317 size_t front() @property @safe const nothrow pure 318 { 319 return _value; 320 } 321 322 /// ditto 323 void popFront() 324 { 325 immutable sum = _cumulativeProportions.back; 326 immutable point = uniform!"[)"(0, sum, _rng); 327 assert(point < sum); 328 _value = _cumulativeProportions.length - _cumulativeProportions.upperBound!search(point).length; 329 } 330 331 /// ditto 332 static if (isForwardRange!UniformRNG) 333 { 334 typeof(this) save() @property 335 { 336 auto ret = new typeof(this)(this); 337 ret._rng = this._rng.save; 338 return ret; 339 } 340 } 341 } 342 343 /// ditto 344 auto discreteDistribution(SearchPolicy search = SearchPolicy.binarySearch, UniformRNG, Range) 345 (UniformRNG rng, Range proportions) 346 if (isInputRange!Range && isNumeric!(ElementType!Range) && isUniformRNG!UniformRNG) 347 { 348 return new DiscreteDistribution!(search, DiceType!Range, UniformRNG)(rng, proportions); 349 } 350 351 /// ditto 352 auto discreteDistribution(SearchPolicy search = SearchPolicy.binarySearch, Range) 353 (Range proportions) 354 if (isInputRange!Range && isNumeric!(ElementType!Range)) 355 { 356 return discreteDistribution(rndGen, proportions); 357 } 358 359 /// ditto 360 auto discreteDistribution(SearchPolicy search = SearchPolicy.binarySearch, UniformRNG, Num) 361 (UniformRNG rng, Num[] proportions...) 362 if (isUniformRNG!UniformRNG && isNumeric!Num) 363 { 364 return discreteDistribution(rng, proportions); 365 } 366 367 /// ditto 368 auto discreteDistribution(SearchPolicy search = SearchPolicy.binarySearch, Num) 369 (Num[] proportions...) 370 if (isNumeric!Num) 371 { 372 return discreteDistribution(rndGen, proportions); 373 } 374 375 unittest 376 { 377 foreach (UniformRNG; UniformRNGTypes) 378 { 379 auto rng = new UniformRNG(unpredictableSeed); 380 381 foreach (immutable d; discreteDistribution(rng, 100.0, 0.0).take(100)) 382 { 383 assert(d == 0); 384 } 385 386 foreach (immutable d; discreteDistribution(rng, 0.0, 100.0).take(100)) 387 { 388 assert(d == 1); 389 } 390 391 foreach (immutable d; discreteDistribution(100, 0).take(100)) 392 { 393 assert(d == 0); 394 } 395 396 foreach (immutable l; 2 .. 100) 397 { 398 auto prop = new uint[l]; 399 prop[] = 0; 400 prop[0] = prop[$-1] = 20; 401 402 foreach (immutable d; discreteDistribution(rng, prop).take(100)) 403 { 404 assert(d == 0 || d == l - 1); 405 } 406 } 407 408 import std.typetuple; 409 410 foreach(T; TypeTuple!(byte, ubyte, short, ushort, int, uint, 411 long, ulong, float, double, real)) 412 { 413 foreach (immutable l; 2 .. 100) 414 { 415 auto prop = uniformDistribution!("[]", T, T)(1, 10, rng).take(10).array; 416 417 foreach (immutable d; discreteDistribution(rng.save, prop).take(100)) 418 { 419 assert(d == dice(rng, prop)); 420 } 421 } 422 } 423 424 // Check .save works 425 { 426 auto ddist1 = discreteDistribution(rng, 10.0, 3.0, 9.0); 427 auto ddist2 = ddist1.save; 428 429 assert(ddist1 !is ddist2); 430 assert(ddist1._rng !is ddist2._rng); 431 432 foreach (d1, d2; lockstep(ddist1.take(100), ddist2.take(100))) 433 { 434 assert(d1 == d2); 435 } 436 } 437 } 438 } 439 440 /** 441 * Returns a floating-point number drawn from a _normal (Gaussian) 442 * distribution with mean $(D mu) and standard deviation $(D sigma). 443 * If no random number generator is specified, the default $(D rndGen) 444 * will be used as the source of randomness. 445 * 446 * Note that this function uses two variates from the uniform random 447 * number generator to generate a single normally-distributed variate. 448 * It is therefore an inefficient means of generating a large number of 449 * normally-distributed variates. If you wish to draw many variates 450 * from the _normal distribution, it is better to use the range-based 451 * $(D normalDistribution) instead. 452 */ 453 auto normal(T1, T2)(T1 mu, T2 sigma) 454 if (isNumeric!T1 && isNumeric!T2) 455 { 456 return normal!(T1, T2, Random)(mu, sigma, rndGen); 457 } 458 459 /// ditto 460 auto normal(T1, T2, UniformRNG)(T1 mu, T2 sigma, UniformRNG rng) 461 if (isNumeric!T1 && isNumeric!T2 && isUniformRNG!UniformRNG) 462 { 463 import std.math; 464 465 static if (isFloatingPoint!(CommonType!(T1, T2))) 466 { 467 alias T = CommonType!(T1, T2); 468 } 469 else 470 { 471 alias T = double; 472 } 473 474 immutable T _r1 = uniform01!T(rng); 475 immutable T _r2 = uniform01!T(rng); 476 477 return sqrt(-2 * log(1 - _r2)) * cos(2 * PI * _r1) * sigma + mu; 478 } 479 480 unittest 481 { 482 // Compare to behaviour of NormalDistribution 483 foreach (UniformRNG; UniformRNGTypes) 484 { 485 auto rng = new UniformRNG(unpredictableSeed); 486 auto ndist = normalDistribution(3.29, 7.64, rng.save); 487 488 static assert(is(CommonType!(double, double) == double)); 489 490 foreach (immutable _; 0 .. 100) 491 { 492 import std.math; 493 auto val = normal(3.29, 7.64, rng); 494 assert(approxEqual(val, ndist.front)); 495 ndist.popFront(); 496 ndist.popFront(); 497 } 498 } 499 } 500 501 /** 502 * Provides an infinite range of random numbers distributed according to the 503 * normal (Gaussian) distribution with mean $(D mu) and standard deviation 504 * $(D sigma). If no random number generator is specified, the default 505 * $(D rndGen) will be used as the source of randomness. 506 */ 507 final class NormalDistribution(T, UniformRNG) 508 if (isFloatingPoint!T && isUniformRNG!UniformRNG) 509 { 510 private: 511 alias NormalEngine = NormalEngineBoxMuller; 512 NormalEngine!T _engine; 513 UniformRNG _rng; 514 T _value; 515 516 public: 517 enum bool isRandomDistribution = true; 518 immutable T mean; 519 immutable T stdev; 520 521 this(T mu, T sigma, UniformRNG rng) 522 { 523 import std.exception; 524 enforce(sigma > 0); 525 mean = mu; 526 stdev = sigma; 527 _rng = rng; 528 popFront(); 529 } 530 531 this(typeof(this) that) 532 { 533 this.mean = that.mean; 534 this.stdev = that.stdev; 535 this._engine = that._engine; 536 this._rng = that._rng; 537 this._value = that._value; 538 } 539 540 /// Range primitives. 541 enum bool empty = false; 542 543 /// ditto 544 T front() @property @safe const nothrow pure 545 { 546 return _value; 547 } 548 549 /// ditto 550 void popFront() 551 { 552 _value = _engine(this.mean, this.stdev, _rng); 553 } 554 555 /// ditto 556 static if (isForwardRange!UniformRNG) 557 { 558 typeof(this) save() @property 559 { 560 auto ret = new typeof(this)(this); 561 ret._rng = this._rng.save; 562 return ret; 563 } 564 } 565 } 566 567 /// ditto 568 auto normalDistribution(T1, T2, UniformRNG) 569 (T1 mu, T2 sigma, UniformRNG rng) 570 if (isNumeric!T1 && isNumeric!T2 && isUniformRNG!UniformRNG) 571 { 572 static if (isFloatingPoint!(CommonType!(T1, T2))) 573 { 574 alias T = CommonType!(T1, T2); 575 } 576 else 577 { 578 alias T = double; 579 } 580 581 return new NormalDistribution!(T, UniformRNG)(mu, sigma, rng); 582 } 583 584 /// ditto 585 auto normalDistribution(T1, T2) 586 (T1 mu, T2 sigma) 587 if (isNumeric!T1 && isNumeric!T2) 588 { 589 return normalDistribution!(T1, T2, Random)(mu, sigma, rndGen); 590 } 591 592 unittest 593 { 594 // check type rules for NormalDistribution 595 { 596 auto ndist = normalDistribution(0, 1); 597 static assert(is(typeof(ndist.front) == double)); 598 } 599 { 600 auto ndist = normalDistribution(0.0f, 1); 601 static assert(is(typeof(ndist.front) == float)); 602 } 603 { 604 auto ndist = normalDistribution(0.0, 1); 605 static assert(is(typeof(ndist.front) == double)); 606 } 607 { 608 auto ndist = normalDistribution(0.0L, 1); 609 static assert(is(typeof(ndist.front) == real)); 610 } 611 612 // check save works effectively 613 foreach (UniformRNG; UniformRNGTypes) 614 { 615 auto rng = new UniformRNG(unpredictableSeed); 616 auto ndist = normalDistribution(3.29, 7.64, rng); 617 /* Box-Muller generates normal variates a pair at a time. 618 * advancing to the second of these helps verify that the 619 * .save method is truly copying the source distribution. 620 */ 621 ndist.popFront(); 622 auto ndist2 = ndist.save; 623 assert(ndist2 !is ndist); 624 625 ndist.popFrontN(10); 626 assert(ndist2.front != ndist.front); 627 ndist2.popFrontN(10); 628 assert(ndist2.front == ndist.front); 629 } 630 } 631 632 /** 633 * Generates random numbers drawn from a normal (Gaussian) distribution, using 634 * the Box-Muller Transform method. 635 * 636 * This implementation of Box-Muller closely follows that of its counterpart 637 * in the Boost.Random C++ library and should produce matching results aside 638 * from discrepancies that arise out of differences in floating-point precision. 639 */ 640 private struct NormalEngineBoxMuller(T) 641 if (isFloatingPoint!T) 642 { 643 private: 644 bool _valid = false; 645 T _rho, _r1, _r2; 646 647 public: 648 /** 649 * Generates a single random number drawn from a normal distribution with 650 * mean $(D mu) and standard deviation $(D sigma), using $(D rng) as the 651 * source of randomness. 652 */ 653 T opCall(UniformRNG)(in T mu, in T sigma, UniformRNG rng) 654 if (isUniformRNG!UniformRNG) 655 { 656 import std.math; 657 658 _valid = !_valid; 659 660 if (_valid) 661 { 662 /* N.B. Traditional Box-Muller asks for random numbers 663 * in (0, 1], which uniform() can readily supply. We 664 * instead generate numbers in [0, 1) and use 1 - num 665 * to match the output of Boost.Random. 666 */ 667 _r1 = uniform01!T(rng); 668 _r2 = uniform01!T(rng); 669 _rho = sqrt(-2 * log(1 - _r2)); 670 671 return _rho * cos(2 * PI * _r1) * sigma + mu; 672 } 673 else 674 { 675 return _rho * sin(2 * PI * _r1) * sigma + mu; 676 } 677 } 678 } 679 680 unittest 681 { 682 NormalEngineBoxMuller!double engine; 683 684 foreach (UniformRNG; UniformRNGTypes) 685 { 686 auto rng1 = new UniformRNG(unpredictableSeed); 687 auto rng2 = rng1.save; 688 auto rng3 = rng1.save; 689 double mu = 6.5, sigma = 3.2; 690 691 /* The Box-Muller engine produces variates a pair at 692 * a time. We verify this is true by using a pair of 693 * pseudo-random number generators sharing the same 694 * initial state. 695 */ 696 auto a1 = engine(mu, sigma, rng1); 697 auto b2 = engine(mu, sigma, rng2); 698 699 // verify that 1st RNG has been called but 2nd has not 700 assert(rng3.front != rng1.front); 701 assert(rng3.front == rng2.front); 702 703 /* Now, calling with the RNG order reversed should 704 * produce the same results: only rng2 will get called 705 * this time. 706 */ 707 auto a2 = engine(mu, sigma, rng2); 708 auto b1 = engine(mu, sigma, rng1); 709 710 assert(a1 == a2); 711 assert(b1 == b2); 712 assert(rng2.front == rng1.front); 713 assert(rng3.front != rng2.front); 714 715 // verify that the RNGs have each been called twice 716 rng3.popFrontN(2); 717 assert(rng3.front == rng2.front); 718 } 719 } 720 721 /** 722 * Generates a number between $(D a) and $(D b). The $(D boundaries) 723 * parameter controls the shape of the interval (open vs. closed on 724 * either side). Valid values for $(D boundaries) are $(D "[]"), $(D 725 * "$(LPAREN)]"), $(D "[$(RPAREN)"), and $(D "()"). The default interval 726 * is closed to the left and open to the right. If no random number 727 * generator is specified, the default $(D rndGen) will be used as the 728 * source of randomness. 729 * 730 * Example: 731 * 732 * ---- 733 * auto gen = Random(unpredictableSeed); 734 * // Generate an integer in [0, 1023] 735 * auto a = uniform(0, 1024, gen); 736 * // Generate a float in [0, 1$(RPAREN) 737 * auto a = uniform(0.0f, 1.0f, gen); 738 * ---- 739 */ 740 auto uniform(string boundaries = "[)", T1, T2) 741 (T1 a, T2 b) 742 if (!is(CommonType!(T1, T2) == void)) 743 { 744 return uniform!(boundaries, T1, T2, Random)(a, b, rndGen); 745 } 746 747 unittest 748 { 749 foreach (UniformRNG; UniformRNGTypes) 750 { 751 auto rng = new UniformRNG(unpredictableSeed); 752 753 foreach (i; 0 .. 20) 754 { 755 auto x = uniform(0.0, 15.0, rng); 756 assert(0 <= x && x < 15); 757 } 758 foreach (i; 0 .. 20) 759 { 760 auto x = uniform!"[]"('a', 'z', rng); 761 assert('a' <= x && x <= 'z'); 762 } 763 764 foreach (i; 0 .. 20) 765 { 766 auto x = uniform('a', 'z', rng); 767 assert('a' <= x && x < 'z'); 768 } 769 770 foreach(i; 0 .. 20) 771 { 772 immutable ubyte a = 0; 773 immutable ubyte b = 15; 774 auto x = uniform(a, b, rng); 775 assert(a <= x && x < b); 776 } 777 } 778 } 779 780 // Implementation of uniform for floating-point types 781 /// ditto 782 auto uniform(string boundaries = "[)", T1, T2, UniformRNG) 783 (T1 a, T2 b, UniformRNG rng) 784 if (isFloatingPoint!(CommonType!(T1, T2)) && isUniformRNG!UniformRNG) 785 out (result) 786 { 787 // We assume "[)" as the common case 788 static if (boundaries[0] == '(') 789 { 790 assert(a < result); 791 } 792 else 793 { 794 assert(a <= result); 795 } 796 797 static if (boundaries[1] == ']') 798 { 799 assert(result <= b); 800 } 801 else 802 { 803 assert(result < b); 804 } 805 } 806 body 807 { 808 import std.exception, std.math, std.string : format; 809 alias NumberType = Unqual!(CommonType!(T1, T2)); 810 static if (boundaries[0] == '(') 811 { 812 NumberType _a = nextafter(cast(NumberType) a, NumberType.infinity); 813 } 814 else 815 { 816 NumberType _a = a; 817 } 818 static if (boundaries[1] == ')') 819 { 820 NumberType _b = nextafter(cast(NumberType) b, -NumberType.infinity); 821 } 822 else 823 { 824 NumberType _b = b; 825 } 826 enforce(_a <= _b, 827 format("hap.random.distribution.uniform(): invalid bounding interval %s%s, %s%s", 828 boundaries[0], a, b, boundaries[1])); 829 NumberType result = 830 _a + (_b - _a) * cast(NumberType) (rng.front - rng.min) 831 / (rng.max - rng.min); 832 rng.popFront(); 833 return result; 834 } 835 836 /* Implementation of uniform for integral types. 837 * 838 * Description of algorithm and suggestion of correctness: 839 * 840 * The modulus operator maps an integer to a small, finite space. For instance, `x 841 * % 3` will map whatever x is into the range [0 .. 3). 0 maps to 0, 1 maps to 1, 2 842 * maps to 2, 3 maps to 0, and so on infinitely. As long as the integer is 843 * uniformly chosen from the infinite space of all non-negative integers then `x % 844 * 3` will uniformly fall into that range. 845 * 846 * (Non-negative is important in this case because some definitions of modulus, 847 * namely the one used in computers generally, map negative numbers differently to 848 * (-3 .. 0]. `uniform` does not use negative number modulus, thus we can safely 849 * ignore that fact.) 850 * 851 * The issue with computers is that integers have a finite space they must fit in, 852 * and our uniformly chosen random number is picked in that finite space. So, that 853 * method is not sufficient. You can look at it as the integer space being divided 854 * into "buckets" and every bucket after the first bucket maps directly into that 855 * first bucket. `[0, 1, 2]`, `[3, 4, 5]`, ... When integers are finite, then the 856 * last bucket has the chance to be "incomplete": `[uint.max - 3, uint.max - 2, 857 * uint.max - 1]`, `[uint.max]` ... (the last bucket only has 1!). The issue here 858 * is that _every_ bucket maps _completely_ to the first bucket except for that 859 * last one. The last one doesn't have corresponding mappings to 1 or 2, in this 860 * case, which makes it unfair. 861 * 862 * So, the answer is to simply "reroll" if you're in that last bucket, since it's 863 * the only unfair one. Eventually you'll roll into a fair bucket. Simply, instead 864 * of the meaning of the last bucket being "maps to `[0]`", it changes to "maps to 865 * `[0, 1, 2]`", which is precisely what we want. 866 * 867 * To generalize, `upperDist` represents the size of our buckets (and, thus, the 868 * exclusive upper bound for our desired uniform number). `rnum` is a uniformly 869 * random number picked from the space of integers that a computer can hold (we'll 870 * say `UpperType` represents that type). 871 * 872 * We'll first try to do the mapping into the first bucket by doing `offset = rnum 873 * % upperDist`. We can figure out the position of the front of the bucket we're in 874 * by `bucketFront = rnum - offset`. 875 * 876 * If we start at `UpperType.max` and walk backwards `upperDist - 1` spaces, then 877 * the space we land on is the last acceptable position where a full bucket can 878 * fit: 879 * 880 * ``` 881 * bucketFront UpperType.max 882 * v v 883 * [..., 0, 1, 2, ..., upperDist - 1] 884 * ^~~ upperDist - 1 ~~^ 885 * ``` 886 * 887 * If the bucket starts any later, then it must have lost at least one number and 888 * at least that number won't be represented fairly. 889 * 890 * ``` 891 * bucketFront UpperType.max 892 * v v 893 * [..., upperDist - 1, 0, 1, 2, ..., upperDist - 2] 894 * ^~~~~~~~ upperDist - 1 ~~~~~~~^ 895 * ``` 896 * 897 * Hence, our condition to reroll is 898 * `bucketFront > (UpperType.max - (upperDist - 1))` 899 */ 900 /// ditto 901 auto uniform(string boundaries = "[)", T1, T2, UniformRNG) 902 (T1 a, T2 b, UniformRNG rng) 903 if ((isIntegral!(CommonType!(T1, T2)) || isSomeChar!(CommonType!(T1, T2))) 904 && isUniformRNG!UniformRNG) 905 out (result) 906 { 907 // We assume "[)" as the common case 908 static if (boundaries[0] == '(') 909 { 910 assert(a < result); 911 } 912 else 913 { 914 assert(a <= result); 915 } 916 917 static if (boundaries[1] == ']') 918 { 919 assert(result <= b); 920 } 921 else 922 { 923 assert(result < b); 924 } 925 } 926 body 927 { 928 import std.conv, std.exception; 929 alias ResultType = Unqual!(CommonType!(T1, T2)); 930 // We handle the case "[)' as the common case, and we adjust all 931 // other cases to fit it. 932 static if (boundaries[0] == '(') 933 { 934 enforce(a < ResultType.max, 935 text("hap.random.distribution.uniform(): invalid left bound ", a)); 936 ResultType lower = cast(ResultType) (a + 1); 937 } 938 else 939 { 940 ResultType lower = a; 941 } 942 943 static if (boundaries[1] == ']') 944 { 945 enforce(lower <= b, 946 text("hap.random.distribution.uniform(): invalid bounding interval ", 947 boundaries[0], a, ", ", b, boundaries[1])); 948 /* Cannot use this next optimization with dchar, as dchar 949 * only partially uses its full bit range 950 */ 951 static if (!is(ResultType == dchar)) 952 { 953 if (b == ResultType.max && lower == ResultType.min) 954 { 955 // Special case - all bits are occupied 956 return uniform!ResultType(rng); 957 } 958 } 959 auto upperDist = unsigned(b - lower) + 1u; 960 } 961 else 962 { 963 enforce(lower < b, 964 text("hap.random.distribution.uniform(): invalid bounding interval ", 965 boundaries[0], a, ", ", b, boundaries[1])); 966 auto upperDist = unsigned(b - lower); 967 } 968 969 assert(upperDist != 0); 970 971 alias UpperType = typeof(upperDist); 972 static assert(UpperType.min == 0); 973 974 UpperType offset, rnum, bucketFront; 975 do 976 { 977 rnum = uniform!UpperType(rng); 978 offset = rnum % upperDist; 979 bucketFront = rnum - offset; 980 } // while we're in an unfair bucket... 981 while (bucketFront > (UpperType.max - (upperDist - 1))); 982 983 return cast(ResultType)(lower + offset); 984 } 985 986 unittest 987 { 988 import std.conv, std.typetuple; 989 990 foreach (UniformRNG; UniformRNGTypes) 991 { 992 auto rng = new UniformRNG(unpredictableSeed); 993 994 auto a = uniform(0, 1024, rng); 995 assert(0 <= a && a <= 1024); 996 auto b = uniform(0.0f, 1.0f, rng); 997 assert(0 <= b && b < 1, to!string(b)); 998 auto c = uniform(0.0, 1.0); 999 assert(0 <= c && c < 1); 1000 1001 foreach (T; TypeTuple!(char, wchar, dchar, byte, ubyte, short, ushort, 1002 int, uint, long, ulong, float, double, real)) 1003 { 1004 foreach (boundaries; TypeTuple!("[)", "(]", "[]", "()")) 1005 { 1006 T lo = 0, hi = 100; 1007 T init = uniform!boundaries(lo, hi, rng); 1008 size_t i = 50; 1009 while (--i && uniform!boundaries(lo, hi, rng) == init) {} 1010 assert(i > 0); 1011 1012 foreach (immutable _; 0 .. 100) 1013 { 1014 auto u1 = uniform!boundaries(lo, hi, rng); 1015 auto u2 = uniform!boundaries(lo, hi); 1016 1017 static if (boundaries[0] == '(') 1018 { 1019 assert(lo < u1); 1020 assert(lo < u2); 1021 } 1022 else 1023 { 1024 assert(lo <= u1); 1025 assert(lo <= u2); 1026 } 1027 1028 static if (boundaries[1] == ']') 1029 { 1030 assert(u1 <= hi); 1031 assert(u2 <= hi); 1032 } 1033 else 1034 { 1035 assert(u1 < hi); 1036 assert(u2 < hi); 1037 } 1038 } 1039 } 1040 1041 /* test case with closed boundaries covering whole range 1042 * of integral type 1043 */ 1044 static if (isIntegral!T || isSomeChar!T) 1045 { 1046 foreach (immutable _; 0 .. 100) 1047 { 1048 auto u = uniform!"[]"(T.min, T.max, rng); 1049 static assert(is(typeof(u) == T)); 1050 assert(T.min <= u, "Lower bound violation for uniform!\"[]\"(" ~ T.stringof ~ ")"); 1051 assert(u <= T.max, "Upper bound violation for uniform!\"[]\"(" ~ T.stringof ~ ")"); 1052 } 1053 } 1054 } 1055 } 1056 1057 auto reproRng = new Xorshift(239842); 1058 1059 foreach (T; TypeTuple!(char, wchar, dchar, byte, ubyte, short, 1060 ushort, int, uint, long, ulong)) 1061 { 1062 foreach (boundaries; TypeTuple!("[)", "(]", "[]", "()")) 1063 { 1064 T lo = T.min + 10, hi = T.max - 10; 1065 T init = uniform!boundaries(lo, hi, reproRng); 1066 size_t i = 50; 1067 while (--i && uniform!boundaries(lo, hi, reproRng) == init) {} 1068 assert(i > 0); 1069 } 1070 } 1071 1072 { 1073 bool sawLB = false, sawUB = false; 1074 foreach (i; 0 .. 50) 1075 { 1076 auto x = uniform!"[]"('a', 'd', reproRng); 1077 if (x == 'a') sawLB = true; 1078 if (x == 'd') sawUB = true; 1079 assert('a' <= x && x <= 'd'); 1080 } 1081 assert(sawLB && sawUB); 1082 } 1083 1084 { 1085 bool sawLB = false, sawUB = false; 1086 foreach (i; 0 .. 50) 1087 { 1088 auto x = uniform('a', 'd', reproRng); 1089 if (x == 'a') sawLB = true; 1090 if (x == 'c') sawUB = true; 1091 assert('a' <= x && x < 'd'); 1092 } 1093 assert(sawLB && sawUB); 1094 } 1095 1096 { 1097 bool sawLB = false, sawUB = false; 1098 foreach (i; 0 .. 50) 1099 { 1100 immutable int lo = -2, hi = 2; 1101 auto x = uniform!"()"(lo, hi, reproRng); 1102 if (x == (lo+1)) sawLB = true; 1103 if (x == (hi-1)) sawUB = true; 1104 assert(lo < x && x < hi); 1105 } 1106 assert(sawLB && sawUB); 1107 } 1108 1109 { 1110 bool sawLB = false, sawUB = false; 1111 foreach (i; 0 .. 50) 1112 { 1113 immutable ubyte lo = 0, hi = 5; 1114 auto x = uniform(lo, hi, reproRng); 1115 if (x == lo) sawLB = true; 1116 if (x == (hi-1)) sawUB = true; 1117 assert(lo <= x && x < hi); 1118 } 1119 assert(sawLB && sawUB); 1120 } 1121 1122 { 1123 foreach (i; 0 .. 30) 1124 { 1125 assert(i == uniform(i, i+1, reproRng)); 1126 } 1127 } 1128 } 1129 1130 /** 1131 * Generates a uniformly-distributed number in the range $(D [T.min, T.max]) 1132 * for any integral type $(D T). If no random number generator is passed, 1133 * uses the default $(D rndGen). 1134 */ 1135 auto uniform(T, UniformRNG)(UniformRNG rng) 1136 if (!is(T == enum) && (isIntegral!T || isSomeChar!T) 1137 && isUniformRNG!UniformRNG) 1138 { 1139 /* dchar does not use its full bit range, so we must 1140 * revert to using uniform with specified bounds 1141 */ 1142 static if (is(T == dchar)) 1143 { 1144 return uniform!"[]"(T.min, T.max, rng); 1145 } 1146 else 1147 { 1148 auto r = rng.front; 1149 rng.popFront(); 1150 static if (T.sizeof <= r.sizeof) 1151 { 1152 return cast(T) r; 1153 } 1154 else 1155 { 1156 static assert(T.sizeof == 8 && r.sizeof == 4); 1157 T r1 = rng.front | (cast(T)r << 32); 1158 rng.popFront(); 1159 return r1; 1160 } 1161 } 1162 } 1163 1164 /// ditto 1165 auto uniform(T)() 1166 if (!is(T == enum) && (isIntegral!T || isSomeChar!T)) 1167 { 1168 return uniform!T(rndGen); 1169 } 1170 1171 unittest 1172 { 1173 import std.typetuple; 1174 foreach(T; TypeTuple!(char, wchar, dchar, byte, ubyte, short, ushort, 1175 int, uint, long, ulong)) 1176 { 1177 T init = uniform!T(); 1178 size_t i = 50; 1179 while (--i && uniform!T() == init) {} 1180 assert(i > 0); 1181 assert(i < 50); 1182 1183 foreach (UniformRNG; UniformRNGTypes) 1184 { 1185 auto rng = new UniformRNG(unpredictableSeed); 1186 init = uniform!T(rng); 1187 i = 50; 1188 while (--i && uniform!T(rng) == init) {} 1189 assert(i > 0); 1190 assert(i < 50); 1191 1192 foreach (immutable _; 0 .. 100) 1193 { 1194 auto u = uniform!T(rng); 1195 static assert(is(typeof(u) == T)); 1196 assert(T.min <= u, "Lower bound violation for uniform!" ~ T.stringof); 1197 assert(u <= T.max, "Upper bound violation for uniform!" ~ T.stringof); 1198 } 1199 } 1200 } 1201 } 1202 1203 /** 1204 * Returns a uniformly selected member of enum $(D E). If no random number 1205 * generator is passed, uses the default $(D rndGen). 1206 */ 1207 auto uniform(E, UniformRNG) 1208 (UniformRNG rng) 1209 if (is(E == enum) && isUniformRNG!UniformRNG) 1210 { 1211 static immutable E[EnumMembers!E.length] members = [EnumMembers!E]; 1212 return members[uniform!"[)"(0, members.length, rng)]; 1213 } 1214 1215 /// Ditto 1216 auto uniform(E)() 1217 if (is(E == enum)) 1218 { 1219 return uniform!E(rndGen); 1220 } 1221 1222 /// 1223 unittest 1224 { 1225 enum Fruit { Apple = 12, Mango = 29, Pear = 72 } 1226 foreach (immutable _; 0 .. 100) 1227 { 1228 foreach (immutable f; [uniform!Fruit(), rndGen.uniform!Fruit()]) 1229 { 1230 assert(f == Fruit.Apple || f == Fruit.Mango || f == Fruit.Pear); 1231 } 1232 } 1233 } 1234 1235 unittest 1236 { 1237 enum Fruit { Apple = 12, Mango = 29, Pear = 72 } 1238 foreach (UniformRNG; UniformRNGTypes) 1239 { 1240 auto rng = new UniformRNG(unpredictableSeed); 1241 foreach (immutable _; 0 .. 100) 1242 { 1243 foreach (immutable f; [uniform!Fruit, rng.uniform!Fruit]) 1244 { 1245 assert(f == Fruit.Apple || f == Fruit.Mango || f == Fruit.Pear); 1246 } 1247 } 1248 } 1249 } 1250 1251 /** 1252 * Provides an infinite sequence of random numbers uniformly distributed between 1253 * $(D a) and $(D b). The $(D boundaries) parameter controls the shape of the 1254 * interval (open vs. closed on either side). Valid values for $(D boundaries) 1255 * are $(D "[]"), $(D "$(LPAREN)]"), $(D "[$(RPAREN)"), and $(D "()"). The 1256 * default interval is closed to the left and open to the right. If no random 1257 * number generator is specified, the default $(D rndGen) will be used as the 1258 * source of randomness. 1259 */ 1260 final class UniformDistribution(string boundaries = "[)", T, UniformRNG) 1261 if ((isNumeric!T || isSomeChar!T) && isUniformRNG!UniformRNG) 1262 { 1263 private: 1264 UniformRNG _rng; 1265 T _value; 1266 1267 public: 1268 enum bool isRandomDistribution = true; 1269 1270 immutable T min; 1271 immutable T max; 1272 1273 this(T a, T b, UniformRNG rng) 1274 { 1275 import std.exception; 1276 enforce(a < b); 1277 min = a; 1278 max = b; 1279 _rng = rng; 1280 popFront(); 1281 } 1282 1283 this(typeof(this) that) 1284 { 1285 this(that.min, that.max, that._rng); 1286 } 1287 1288 /// Range primitives. 1289 enum bool empty = false; 1290 1291 /// ditto 1292 T front() @property @safe const nothrow pure 1293 { 1294 return _value; 1295 } 1296 1297 /// ditto 1298 void popFront() 1299 { 1300 _value = uniform!(boundaries, T, T, UniformRNG)(min, max, _rng); 1301 } 1302 1303 /// ditto 1304 static if (isForwardRange!UniformRNG) 1305 { 1306 typeof(this) save() @property 1307 { 1308 auto ret = new typeof(this)(this); 1309 ret._rng = this._rng.save; 1310 return ret; 1311 } 1312 } 1313 } 1314 1315 /// ditto 1316 auto uniformDistribution(string boundaries = "[)", T1, T2, UniformRNG) 1317 (T1 a, T2 b, UniformRNG rng) 1318 if ((isNumeric!(CommonType!(T1, T2)) || isSomeChar!(CommonType!(T1, T2))) 1319 && isUniformRNG!UniformRNG) 1320 { 1321 alias T = CommonType!(T1, T2); 1322 return new UniformDistribution!(boundaries, T, UniformRNG)(a, b, rng); 1323 } 1324 1325 /// ditto 1326 auto uniformDistribution(string boundaries = "[)", T1, T2) 1327 (T1 a, T2 b) 1328 if (isNumeric!(CommonType!(T1, T2)) || isSomeChar!(CommonType!(T1, T2))) 1329 { 1330 alias T = CommonType!(T1, T2); 1331 return new UniformDistribution!(boundaries, T, Random)(a, b, rndGen); 1332 } 1333 1334 unittest 1335 { 1336 // General tests 1337 foreach (UniformRNG; UniformRNGTypes) 1338 { 1339 import std.typetuple; 1340 1341 foreach (T; TypeTuple!(char, wchar, dchar, byte, ubyte, short, ushort, 1342 int, uint, long, ulong, float, double, real)) 1343 { 1344 foreach (boundaries; TypeTuple!("[)", "(]", "[]", "()")) 1345 { 1346 static assert(isRandomDistribution!(UniformDistribution!(boundaries, T, UniformRNG))); 1347 1348 T min = 0, max = 10; 1349 auto rng = new UniformRNG(unpredictableSeed); 1350 1351 foreach (u; uniformDistribution!boundaries(min, max, rng.save).take(100)) 1352 { 1353 assert(u == uniform!boundaries(min, max, rng)); 1354 } 1355 } 1356 } 1357 } 1358 1359 // check distribution boundaries function OK for integers 1360 { 1361 auto udist = uniformDistribution(0, 10); 1362 size_t eqMin = 0; 1363 foreach (u; udist.take(100)) 1364 { 1365 assert(udist.min <= u); 1366 assert(u < udist.max); 1367 if (u == udist.min) ++eqMin; 1368 } 1369 assert(eqMin > 0); 1370 } 1371 { 1372 auto udist = uniformDistribution!"()"(0, 10); 1373 foreach (u; udist.take(100)) 1374 { 1375 assert(udist.min < u); 1376 assert(u < udist.max); 1377 } 1378 } 1379 { 1380 auto udist = uniformDistribution!"(]"(0, 10); 1381 size_t eqMax = 0; 1382 foreach (u; udist.take(100)) 1383 { 1384 assert(udist.min < u); 1385 assert(u <= udist.max); 1386 if (u == udist.max) ++eqMax; 1387 } 1388 assert(eqMax > 0); 1389 } 1390 { 1391 auto udist = uniformDistribution!"[]"(0, 10); 1392 size_t eqMin = 0, eqMax = 0; 1393 foreach (u; udist.take(100)) 1394 { 1395 assert(udist.min <= u); 1396 assert(u <= udist.max); 1397 if (u == udist.min) ++eqMin; 1398 if (u == udist.max) ++eqMax; 1399 } 1400 assert(eqMin > 0); 1401 assert(eqMax > 0); 1402 } 1403 1404 // check that save works properly 1405 { 1406 auto udist = uniformDistribution(1.1, 3.3); 1407 auto udist2 = udist.save; 1408 assert(udist2 !is udist); 1409 udist.popFrontN(20); 1410 assert(udist2.front != udist.front); 1411 udist2.popFrontN(20); 1412 assert(udist2.front == udist.front); 1413 } 1414 } 1415 1416 /** 1417 * Generates an infinite sequence of uniformly-distributed numbers in the 1418 * range $(D [T.min, T.max]) for any integral type $(D T). If no random 1419 * number generator is specified, the default $(D rndGen) will be used as 1420 * the source of randomness. 1421 */ 1422 final class UniformDistribution(T, UniformRNG) 1423 if (!is(T == enum) && (isIntegral!T || isSomeChar!T) 1424 && isUniformRNG!UniformRNG) 1425 { 1426 private: 1427 UniformRNG _rng; 1428 T _value; 1429 1430 public: 1431 enum bool isRandomDistribution = true; 1432 1433 enum T min = T.min; 1434 enum T max = T.max; 1435 1436 this(UniformRNG rng) 1437 { 1438 _rng = rng; 1439 popFront(); 1440 } 1441 1442 this(typeof(this) that) 1443 { 1444 this._rng = that._rng; 1445 this._value = that._value; 1446 } 1447 1448 /// Range primitives. 1449 enum bool empty = false; 1450 1451 /// ditto 1452 T front() @property @safe const nothrow pure 1453 { 1454 return _value; 1455 } 1456 1457 /// ditto 1458 void popFront() 1459 { 1460 _value = uniform!(T, UniformRNG)(_rng); 1461 } 1462 1463 /// ditto 1464 static if (isForwardRange!UniformRNG) 1465 { 1466 typeof(this) save() @property 1467 { 1468 auto ret = new typeof(this)(this); 1469 ret._rng = this._rng.save; 1470 return ret; 1471 } 1472 } 1473 } 1474 1475 /// ditto 1476 auto uniformDistribution(T, UniformRNG) 1477 (UniformRNG rng) 1478 if (!is(T == enum) && (isIntegral!T || isSomeChar!T) 1479 && isUniformRNG!UniformRNG) 1480 { 1481 return new UniformDistribution!(T, UniformRNG)(rng); 1482 } 1483 1484 /// ditto 1485 auto uniformDistribution(T)() 1486 if (!is(T == enum) && (isIntegral!T || isSomeChar!T)) 1487 { 1488 return new UniformDistribution!(T, Random)(rndGen); 1489 } 1490 1491 unittest 1492 { 1493 foreach (UniformRNG; UniformRNGTypes) 1494 { 1495 import std.typetuple; 1496 1497 foreach (T; TypeTuple!(char, wchar, dchar, byte, ubyte, short, ushort, 1498 int, uint, long, ulong)) 1499 { 1500 static assert(isRandomDistribution!(UniformDistribution!(T, UniformRNG))); 1501 1502 auto rng = new UniformRNG(unpredictableSeed); 1503 auto udist = uniformDistribution!T(rng.save); 1504 1505 foreach (u; udist.take(100)) 1506 { 1507 assert(uniform!T(rng) == u); 1508 assert(u <= T.max); 1509 assert(u >= T.min); 1510 } 1511 1512 // check that .save works 1513 auto udist2 = udist.save; 1514 assert(udist2 !is udist); 1515 foreach (u1, u2; lockstep(udist.take(100), udist2.take(100))) 1516 { 1517 assert(u1 == u2); 1518 } 1519 } 1520 } 1521 } 1522 1523 /** 1524 * Generates an infinite sequence of uniformly selected members of 1525 * enum $(D E). If no random number generator is specified, the 1526 * default $(D rndGen) will be used as the source of randomness. 1527 */ 1528 final class UniformDistribution(E, UniformRNG) 1529 if (is(E == enum) && isUniformRNG!UniformRNG) 1530 { 1531 private: 1532 UniformRNG _rng; 1533 E _value; 1534 1535 public: 1536 enum bool isRandomDistribution = true; 1537 1538 enum E min = E.min; 1539 enum E max = E.max; 1540 1541 this(UniformRNG rng) 1542 { 1543 _rng = rng; 1544 popFront(); 1545 } 1546 1547 this(typeof(this) that) 1548 { 1549 this._rng = that._rng; 1550 this._value = that._value; 1551 } 1552 1553 /// Range primitives. 1554 enum bool empty = false; 1555 1556 /// ditto 1557 E front() @property @safe const nothrow pure 1558 { 1559 return _value; 1560 } 1561 1562 /// ditto 1563 void popFront() 1564 { 1565 _value = uniform!(E, UniformRNG)(_rng); 1566 } 1567 1568 /// ditto 1569 static if (isForwardRange!UniformRNG) 1570 { 1571 typeof(this) save() @property 1572 { 1573 auto ret = new typeof(this)(this); 1574 ret._rng = this._rng.save; 1575 return ret; 1576 } 1577 } 1578 } 1579 1580 /// ditto 1581 auto uniformDistribution(E, UniformRNG) 1582 (UniformRNG rng) 1583 if (is(E == enum) && isUniformRNG!UniformRNG) 1584 { 1585 return new UniformDistribution!(E, UniformRNG)(rng); 1586 } 1587 1588 /// ditto 1589 auto uniformDistribution(E)() 1590 if (is(E == enum)) 1591 { 1592 return new UniformDistribution!(E, Random)(rndGen); 1593 } 1594 1595 /// 1596 unittest 1597 { 1598 enum Fruit { Apple = 12, Mango = 29, Pear = 72 } 1599 1600 foreach (immutable f; uniformDistribution!Fruit().take(100)) 1601 { 1602 assert(f == Fruit.Apple || f == Fruit.Mango || f == Fruit.Pear); 1603 } 1604 } 1605 1606 unittest 1607 { 1608 enum Fruit { Apple = 12, Mango = 29, Pear = 72 } 1609 1610 foreach (UniformRNG; UniformRNGTypes) 1611 { 1612 auto rng = new UniformRNG(unpredictableSeed); 1613 foreach (immutable f; uniformDistribution!Fruit(rng).take(100)) 1614 { 1615 assert(f == Fruit.Apple || f == Fruit.Mango || f == Fruit.Pear); 1616 } 1617 1618 // check that .save works 1619 auto udist1 = uniformDistribution!Fruit(rng); 1620 auto udist2 = udist1.save; 1621 assert(udist2 !is udist1); 1622 foreach (u1, u2; lockstep(udist1.take(100), udist2.take(100))) 1623 { 1624 assert(u1 == u2); 1625 } 1626 } 1627 } 1628 1629 /** 1630 * Generates a uniformly-distributed floating point number of type 1631 * $(D T) in the range [0, 1). If no random number generator is 1632 * specified, the default RNG $(D rndGen) will be used as the source 1633 * of randomness. 1634 * 1635 * $(D uniform01) offers a faster generation of random variates than 1636 * the equivalent $(D uniform!"[)"(0.0, 1.0)) and so may be preferred 1637 * for some applications. 1638 */ 1639 T uniform01(T = double)() 1640 if (isFloatingPoint!T) 1641 { 1642 return uniform01!T(rndGen); 1643 } 1644 1645 /// ditto 1646 T uniform01(T = double, UniformRNG)(UniformRNG rng) 1647 if (isFloatingPoint!T && isUniformRNG!UniformRNG) 1648 out (result) 1649 { 1650 assert(0 <= result); 1651 assert(result < 1); 1652 } 1653 body 1654 { 1655 alias R = typeof(rng.front); 1656 static if (isIntegral!R) 1657 { 1658 enum T factor = 1 / (cast(T) 1 + rng.max - rng.min); 1659 } 1660 else static if (isFloatingPoint!R) 1661 { 1662 enum T factor = 1 / (rng.max - rng.min); 1663 } 1664 else 1665 { 1666 static assert(false); 1667 } 1668 1669 while (true) 1670 { 1671 immutable T u = (rng.front - rng.min) * factor; 1672 rng.popFront(); 1673 if (u < 1) 1674 { 1675 return u; 1676 } 1677 } 1678 1679 // Shouldn't ever get here. 1680 assert(false); 1681 } 1682 1683 unittest 1684 { 1685 foreach (UniformRNG; UniformRNGTypes) 1686 { 1687 import std.typetuple; 1688 1689 foreach (T; TypeTuple!(float, double, real)) 1690 { 1691 UniformRNG rng = new UniformRNG(unpredictableSeed); 1692 1693 auto a = uniform01(); 1694 assert(is(typeof(a) == double)); 1695 assert(0 <= a && a < 1); 1696 1697 auto b = uniform01(rng); 1698 assert(is(typeof(a) == double)); 1699 assert(0 <= b && b < 1); 1700 1701 auto c = uniform01!T(); 1702 assert(is(typeof(c) == T)); 1703 assert(0 <= c && c < 1); 1704 1705 auto d = uniform01!T(rng); 1706 assert(is(typeof(d) == T)); 1707 assert(0 <= d && d < 1); 1708 1709 T init = uniform01!T(rng); 1710 size_t i = 50; 1711 while (--i && uniform01!T(rng) == init) {} 1712 assert(i > 0); 1713 assert(i < 50); 1714 } 1715 } 1716 } 1717 1718 /** 1719 * Provides an infinite sequence of random numbers uniformly distributed in the 1720 * interval [0, 1). If no RNG is specified, $(D uniformDistribution) will use 1721 * the default generator $(D rndGen). 1722 */ 1723 final class Uniform01Distribution(T, UniformRNG) 1724 if (isFloatingPoint!T && isUniformRNG!UniformRNG) 1725 { 1726 private: 1727 UniformRNG _rng; 1728 T _value; 1729 1730 public: 1731 enum T min = 0; 1732 enum T max = 1; 1733 enum bool isRandomDistribution = true; 1734 1735 this(UniformRNG rng) 1736 { 1737 _rng = rng; 1738 popFront(); 1739 } 1740 1741 this(typeof(this) that) 1742 { 1743 this._rng = that._rng; 1744 this._value = that._value; 1745 } 1746 1747 /// Range primitives. 1748 enum bool empty = false; 1749 1750 /// ditto 1751 T front() @property @safe const nothrow pure 1752 { 1753 return _value; 1754 } 1755 1756 /// ditto 1757 void popFront() 1758 { 1759 _value = uniform01!(T, UniformRNG)(_rng); 1760 } 1761 1762 /// ditto 1763 static if (isForwardRange!UniformRNG) 1764 { 1765 typeof(this) save() @property 1766 { 1767 auto ret = new typeof(this)(this); 1768 ret._rng = this._rng.save; 1769 return ret; 1770 } 1771 } 1772 } 1773 1774 /// ditto 1775 auto uniform01Distribution(T = double, UniformRNG)(UniformRNG rng) 1776 if (isFloatingPoint!T && isUniformRNG!UniformRNG) 1777 { 1778 return new Uniform01Distribution!(T, UniformRNG)(rng); 1779 } 1780 1781 /// ditto 1782 auto uniform01Distribution(T = double)() 1783 if (isFloatingPoint!T) 1784 { 1785 return new Uniform01Distribution!(T, Random)(rndGen); 1786 } 1787 1788 unittest 1789 { 1790 foreach (immutable u; uniform01Distribution().take(1_000_000)) 1791 { 1792 assert(0 <= u); 1793 assert(u < 1); 1794 } 1795 1796 foreach (UniformRNG; UniformRNGTypes) 1797 { 1798 import std.typetuple; 1799 1800 foreach (T; TypeTuple!(float, double, real)) 1801 { 1802 auto rng = new UniformRNG; 1803 1804 foreach (immutable u; uniform01Distribution!T(rng.save).take(100)) 1805 { 1806 assert(u == uniform01!T(rng)); 1807 assert(0 <= u); 1808 assert(u < 1); 1809 } 1810 1811 // check that .save works 1812 auto udist1 = uniform01Distribution(rng); 1813 auto udist2 = udist1.save; 1814 assert(udist2 !is udist1); 1815 foreach (u1, u2; lockstep(udist1.take(100), udist2.take(100))) 1816 { 1817 assert(u1 == u2); 1818 } 1819 } 1820 } 1821 }