For the sake of interest, it's pretty straightforward to generate normally distributed random numbers from a uniform RNG (though it must be done in pairs):
Random rng = new Random();
double r = Math.Sqrt(-2 * Math.Log(rng.NextDouble()));
double θ = 2 * Math.PI * rng.NextDouble();
double x = r * Math.Cos(θ);
double y = r * Math.Sin(θ);
x
and y
now contain two independent, normally distributed random numbers with mean 0 and variance 1. You can scale and translate them as necessary to get the range you want (as interjay explains).
Explanation:
This method is called the Box–Muller transform. It uses the property of the two-dimensional unit Gaussian that the density value itself, p = exp(-r^2/2)
, is uniformly distributed between 0
and 1
(normalisation constant removed for simplicity).
Since you can generate such a value easily using a uniform RNG, you end up with a circular contour of radius r = sqrt(-2 * log(p))
. You can then generate a second uniform random variate between 0
and 2*pi
to give you an angle θ
that defines a unique point on your circular contour. Finally, you can generate two i.i.d. normal random variates by transforming from polar coordinates (r, θ)
back into cartesian coordinates (x, y)
.
This property – that p
is uniformly distributed – doesn't hold for other dimensionalities, which is why you have to generate exactly two normal variates at a time.