Why im getting 2 different results on the same seed number?

Question:

I tried two different ways to get a coin flip result, seeding the RNG first in order to get reproducible results.

First, I tried using random.randint:

import random

random.seed(23412)

flip = random.randint(0,1)
if flip == 0:
    print("Tails")
else:
    print("Heads")

For this seed, I get a Heads result; the flip result is 1.

Then, I tried rounding the result of random.random:

import random

random.seed(23412)

flip = random.random()
print(flip) # for testing purposes
new_flip = round(flip)

if new_flip == 0:
    print("Tails")
else:
    print("Heads")

This time, I get a value for flip of 0.27484468113952387, which rounds to 0, i.e. a Tails result.

Why does the result differ? Shouldn’t random.randint pull the same random value (since the seed was the same), and flip the coin the same way?

Asked By: WildSpaceCadet

||

Answers:

Once you set a seed, all random numbers that follow will be consistent. It does not mean that all random numbers will be the same (and not be random any more).

However, once you re-set the seed, the random number generation will start from the beginning. Therefore it’s predictable what will happen, e.g. like this, where 200 random numbers are generated in a 100 loops and I can predict each outcome (via assertions)

import random

for i in range(100):
    test_seed = 23412
    random.seed(test_seed)

    flip = round(random.random())
    assert flip == 0                # predict "Tails"
    if flip == 0:
        print("Tails")
    else:
        print("Heads")

    flip = random.randint(0,1)
    assert flip == 1                # predict "Heads"
    if flip == 0:
        print("Tails")
    else:
        print("Heads")
Answered By: Thomas Weller

Seeding a random number generator ensures a reproducible stream of underlying raw data. Different random module methods will compute their results in different ways, using different amounts of data.

The exact computation is an implementation detail. In the implementation I use (although I suspect it is the same for many other versions), random.randint will use the next single bit of raw data from the stream – it does a bunch of math first to figure out how many possible answers there are in range, then rounds that up to the next power of two, then chooses the corresponding number of bits to get a value (0..2n-1), repeats that until it’s in range, and finally does more math to scale that to the original range. (If you tried, for example, random.randint(0, 2), it would repeatedly grab two bits interpreted as an integer, until the result isn’t 3 which is out of range.)

The implementation of random.random is hidden in the C code, but I assume that it grabs multiple bits of data (at least 53) in order to fill the mantissa of a machine double-precision floating-point value.

Answered By: Karl Knechtel