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