1 /**
2 Random generator.
3 */
4 module karasux.random;
5 
6 import std.math : log, cos, PI, sqrt;
7 import std.random : uniform, rndGen;
8 import std.traits : isFloatingPoint;
9 
10 /**
11 Generate Gaussian distribution random number.
12 
13 Params:
14     T = number type.
15     UniformRandomNumberGenerator = random generator.
16     urng = random generator value.
17 Returns;
18     random value.
19 */
20 T gaussianDistributionRandom(T, UniformRandomNumberGenerator)(ref UniformRandomNumberGenerator urng)
21     if (isFloatingPoint!T)
22 {
23     immutable x = uniform!("()", T, T)(cast(T) 0.0, cast(T) 1.0, urng);
24     immutable y = uniform!("()", T, T)(cast(T) 0.0, cast(T) 1.0, urng);
25     return sqrt((cast(T) -2.0) * log(x)) * cos(PI * (cast(T) 2.0) * y);
26 }
27 
28 ///
29 @safe unittest
30 {
31     import std.math : isClose;
32     import std.random : isUniformRNG;
33 
34     struct Rng 
35     {
36         @property real front() const @nogc nothrow pure @safe scope { return 0.5; }
37         @property bool empty() const @nogc nothrow pure @safe scope { return false; }
38         void popFront() @nogc nothrow pure @safe scope {}
39         enum isUniformRandom = true;
40         enum max = 1.0;
41         enum min = 0.0;
42     }
43     static assert(isUniformRNG!Rng);
44 
45     auto rng = Rng();
46     immutable result1 = gaussianDistributionRandom!real(rng);
47     assert(result1.isClose(cast(real) -0x9.6b55f2257e218fep-3));
48     immutable result2 = gaussianDistributionRandom!real(rng);
49     assert(result2.isClose(cast(real) -0x9.6b55f2257e218fep-3));
50 }
51 
52 /**
53 Generate Gaussian distribution random number.
54 
55 Params:
56     T = number type.
57 Returns;
58     random value.
59 */
60 T gaussianDistributionRandom(T)()
61 {
62     return gaussianDistributionRandom!T(rndGen);
63 }
64 
65 ///
66 @safe unittest
67 {
68     auto value = gaussianDistributionRandom!real;
69     static assert(is(typeof(value) == real));
70 
71     /*
72     import std.math : round;
73     import std.stdio : writefln;
74     import std.range : generate, take, repeat;
75     import std.array : array;
76     import std.algorithm : count, filter, sort;
77 
78     auto values = generate!(() => gaussianDistributionRandom!real()).take(100000);
79     size_t[int] histogram;
80     foreach (v; values)
81     {
82         histogram.update(cast(int) round(v * 10.0), () => 1, (size_t n) => n + 1);
83     }
84 
85     foreach (i; histogram.byKey.array.sort)
86     {
87         writefln("%3d: %s", i, '*'.repeat(histogram[i] / 100));
88     }
89     */
90 }
91