digitalmars.D.bugs - [Issue 5901] New: std.random.normal(), std.random.fastNormal()
- d-bugmail puremagic.com (128/128) Apr 27 2011 http://d.puremagic.com/issues/show_bug.cgi?id=5901
http://d.puremagic.com/issues/show_bug.cgi?id=5901 Summary: std.random.normal(), std.random.fastNormal() Product: D Version: D2 Platform: All OS/Version: All Status: NEW Severity: enhancement Priority: P2 Component: Phobos AssignedTo: nobody puremagic.com ReportedBy: bearophile_hugs eml.cc I suggest to add a very commonly useful random generator with normal distribution to std.random. This is a possible API and some implementation ideas (not tested much but there is debug code that performs a visual test. This doesn't replace more rigorous tests but it's useful as sanity test for them): // for std.random import std.math: sqrt, log, cos, PI, isnan; import std.traits: isFloatingPoint, CommonType; import std.random: rndGen, Xorshift; /** Generates a number with normal distribution, with specified mean, standard deviation and random generator (mean and standard deviation must be floating point values). */ CommonType!(T1,T2) normal(T1, T2, UniformRandomNumberGenerator) (T1 mean, T2 stdDev, ref UniformRandomNumberGenerator urng) if (isFloatingPoint!T1 & isFloatingPoint!T2) { alias typeof(return) T; enum T fmax = cast(T)(typeof(urng.front()).max); T r1 = void; do { r1 = urng.front() / fmax; urng.popFront(); } while (r1 <= 0.0); T r2 = urng.front() / fmax; urng.popFront(); return mean + stdDev * sqrt(-2 * log(r1)) * cos(2 * PI * r2); } /// As above, but uses the default generator rndGen. CommonType!(T1,T2) normal(T1, T2)(T1 mean, T2 stdDev) if (isFloatingPoint!T1 & isFloatingPoint!T2) { return normal(mean, stdDev, rndGen); } /// As above, but uses a less precise algorithm, and a fast random generator. CommonType!(T1,T2) fastNormal(T1, T2)(T1 mean, T2 stdDev) if (isFloatingPoint!T1 & isFloatingPoint!T2) { // this is meant to be as fast as possible ... // uses Xorshift too } // There is a faster algorithm to compute normal values, // for fastNormal() too, but it requires a static variable. // For a normalDistribution() it doesn't need a static variable /* // When x and y are two variables from [0, 1), uniformly // distributed, then // // cos(2*pi*x)*sqrt(-2*log(1-y)) // sin(2*pi*x)*sqrt(-2*log(1-y)) // // are two *independent* variables with normal distribution // (mu = 0, sigma = 1). // (Lambert Meertens) // Code adapted from Python random module. alias typeof(return) T; enum T fmax = cast(T)(typeof(urng.front()).max); static double gauss_next; // nan auto z = gauss_next; gauss_next = double.init; // nan if (isnan(z)) { T x2pi = (urng.front() / fmax) * PI * 2; urng.popFront(); T g2rad = sqrt(-2.0 * log(1.0 - (urng.front() / fmax))); urng.popFront(); z = cos(x2pi) * g2rad; gauss_next = sin(x2pi) * g2rad; } return mu + z * sigma; */ debug { // Debug of normal() import std.stdio; void main() { { writeln("Debug of normal(,):"); auto bins = new int[30]; foreach (i; 0 .. 500) { auto r = cast(int)normal(bins.length / 2.0f, 5.0f); if (r < 0) r = 0; if (r > (bins.length - 1)) r = bins.length - 1; bins[r]++; } foreach (count; bins) { write(">"); foreach (i; 0 .. count) write("*"); writeln(); } writeln("\n\n"); } { writeln("Debug of normal(,,Xorshift):"); auto gen = Xorshift(1); auto bins = new int[30]; foreach (i; 0 .. 500) { auto r = cast(int)normal(bins.length / 2.0L, 5.0L, gen); if (r < 0) r = 0; if (r > (bins.length - 1)) r = bins.length - 1; bins[r]++; } foreach (count; bins) { write(">"); foreach (i; 0 .. count) write("*"); writeln(); } writeln(); } } } -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Apr 27 2011