
Random Normally Distributed Numbers
Uniform & Normal Distributions
February 18, 2024
Math.random() in JavaScript returns a random number from a set of numbers that follows a uniform distribution. This means that any number from 0 to 1 is equally likely to be returned. In most instances, this is a desirable effect; most of the time, we want any and all numbers to have an equal probability of occurring.
You can see from the following chart that this is the case.
We’re taking 10,000 random numbers and plotting their value along the vertical axis. It’s simple to observe that the selection yields a distribution of values that is very uniform.
However, it may not always be desirable to generate a random number with an equal distribution. Not everything in the real world needs or has a uniform distribution. Sometimes it’s desirable to generate random values with a normal distribution.
Luckily for us, some really smart people have figured out that there is a way to map a uniformly distributed set to a normally distributed set. The method is called the Box-Muller Transform. It’s a method that allows us to convert a pair of values from a uniform distribution to a single value that is part of a normal distribution.
The formula is:
\[ Z_{1} = \sqrt{-2 * \ln(u)}\cos(2\pi v) \\ Z_{2} = \sqrt{-2 * \ln(u)}\sin(2\pi v) \]
Where \(u\) and \(v\) are random numbers from a uniformly distributed set. While the Box-Muller transform defines two formulas, practically speaking, we may only need to use one of them to generate a normally distributed random number.
We can use the Box-Muller transform formula in our language of preference to generate a normally distributed number, with special consideration to ensure that neither \(u\) nor \(v\) are zero.
function nonZeroNumberRandomNumber(): number {
let u = 0;
while (u == 0) { u = Math.random(); }
return u;
;
}
/**
* Generate a random number with a normal distribution.
* - Mean of 0.
* - Standard deviation of 1.
*/
function normalRandomNumber(): number {
const u = nonZeroNumberRandomNumber();
const v = nonZeroNumberRandomNumber();
const r = Math.sqrt(-2 * Math.log(u));
const theta = 2 * Math.PI * v()
return r * Math.cos(theta);
}