Generating random numbers with Lehmer RNGs
Taking a look at a quick and dirty little random number generator that's great for procedural generation.
The Lehmer RNG
A Lehmer RNG is a type of linear congruential generator (LCG) named after D. H. Miller.
This particular RNG is also sometimes called the Park-Miller RNG after Stephen K. Park and Keith W. Miller, who came up with the specific parameters for the calculation.
Lehmer RNGs are very easy to create, and they provide suitable random numbers for many applications (I use similar constructs whenever I need random values for world generation in game code). One nice benefit of the simplicity of the system is that these generators work great for procedural generation due to the usage of a seed value.
How the Lehmer RNG works
The math is very simple. First, we start by assigning some seed
value.
Any time we want a random number, we use the following formula:
To understand what \(a\) and \(m\) represent, I highly recommend reading through the wikipedia article linked at the bottom of this post1.
The resulting value \(seed_{n+1}\) is both our random number and the input seed (\(seed_{n}\)) for the next random number. This is the linear part of the LCG.
Stephen K. Park and Keith W. Miller (after some revisions) proposed the following values for their Lehmar RNG:
- \(a\): 48,271
- \(m\): \(2^{31}-1\), or \(2,147,483,647\) (
0x7FFFFFFF
in hexadecimal)
One last note: the initial seed value, \(seed_{0}\) must be coprime with the selected values for \(m\)!
An Implementation in rust
The Lehmer RNG
Due to the simplicity of the Lehmer RNG, it's very easy to create one for use in your projects. In this example, I chose a seed arbitrarily (which means each time I run the program, the same values are generated).
Using our Lehmer RNG
We'll write some code to test our RNG. We generate 100,000 random numbers, and track the highest and lowest values that we generate -- in this case using the next_f32()
function which returns a floating point value between 0 and 1.
Hopefull the min and max values are close to 0 and 1 respectively!
Output:
That's well within acceptable range for use in game development!