[Issue 5901] New: std.random.normal(), std.random.fastNormal()
d-bugmail at puremagic.com
d-bugmail at puremagic.com
Wed Apr 27 12:19:31 PDT 2011
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 at puremagic.com
ReportedBy: bearophile_hugs at eml.cc
--- Comment #0 from bearophile_hugs at eml.cc 2011-04-27 12:15:44 PDT ---
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: -------
More information about the Digitalmars-d-bugs
mailing list