Here's some code:
#include <iostream>
int main() {
srand(1);
std::cout << rand() << "\n";
srand(UINT_MAX);
std::cout << rand() << "\n";
}
This produces the following output:
16807
16807
Why do these two seeds produce the same result? The entire sequence of values they produce on successive rand()
calls is also identical. The range of possible values is too large for this to be a pure coincidence. Is it:
rand()
(and if so, I'm curious what that might be)(Possibly related: the seeds 10, 100, 1000, 10000, and 100000 produce 168070, 1680700, 16807000, 168070000, and 1680700000 respectively.)
A very simple usable random number generator is a Lehmer number generator. This RNG is maybe the simplest to implement in software, which is still usable, so probably it has the most issues with randomness, and most easy to analyze.
The number 16807 (aka the fifth power of 7) is associated with Lehmer RNG, because it was used in one of the earliest implementations in 1988 - apparently still in use today!
The formula for Nth random number is (using ^
for exponentiation):
R(n) = (seed * (16807 ^ n)) mod (2 ^ 31 - 1)
If you set seed = 1, n = 1:
R(1) = 16807 mod (2 ^ 31 - 1) = 16807
If you set seed = 2 ^ 32 - 1
:
R(1) =
(2 ^ 32 - 1) * 16807 ≡ (expressing 2^32 = 2^31 * 2)
((2 ^ 31 - 1) * 2 + 1) * 16807 ≡ (distributive law)
(2 ^ 31 - 1) * 2 * 16807 + 1 * 16807 ≡ (modulo 2^31-1)
16807
Here the equality of the first number in the random sequence is because the modulo-number in the Lehmer RNG is almost a power of 2 (2^31-1
), and your seed is also almost a power of 2 (2^32-1
).
The same would happen for seed = 2^31
.
tl;dr: rand()
is known to be that bad.
The actual values are implementation defined. I get the following values on my platform:
seed: 1 : 41
seed: 4294967295 : 35
seed: 10 : 71
seed: 100 : 365
seed: 1000 : 3304
seed: 10000 : 32694
rand()
can be relied on to look somewhat random to a casual user in a hurry. It is not portably suitable for anything else.
The implementation usually use a low quality generator (most often Linear Congruential with bad constants).
The required numeric range is 0...32767, and while implementation may they usually don't exceed that - so you can expect many seeds to result in the same value.
For C++ modern, see <random>
for reliable options.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With