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!"[&#41;"(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 }