Pseudorandom numbers¶

We can generate psedorandom numbers by generating a sequence of random-seeming numbers. This is what Python's random.random() does. One way to generate pseudo-random numbers is to use a linear congruential generator: we repeatedly compute x using

    x = (a*x+b) % m

This will generate random seeming numbers:

In [1]:
a = 1664525
b = 1013904223
m = 2**32 - 1
x = 1
In [2]:
for i in range(10):
    x = (a*x+b) % m
    print(x)
1015568748
1586399053
170058213
3046353778
158472183
2212922578
3231609888
2113058113
157256853
2195350273

If we want numbers in the range 0..1, we can divide by m:

In [3]:
for i in range(10):
    x = (a*x+b) % m
    print(x/m)
0.5629632420751646
0.6265831362983638
0.5310150069489644
0.990509697932403
0.39101890600077316
0.9805789098564021
0.34599670054064985
0.39403539812053445
0.00712455553168537
0.2368643514897824

Usually, when generating pseudo-random numbers this way, we'll only take the middle digits of x. Note that if we are not careful, the last digit can seem non-random: for example, we m is even and we start with an x = 1 and a even, we'll always get an odd last digit:

In [6]:
a = 1664524
b = 0
m = 2**32 
x = 1
In [7]:
for i in range(10):
    x = (a*x+b) % m
    print(x)
1664524
386240656
1777084096
3611447552
1818348544
4158492672
4123181056
3718316032
2307653632
982515712

The seed determines where we start the sequence of pseudo-random numbers. Above, we started with x = 1.

If we want consistent output across runs, we'll set the seed to some set number.

If we want to get a different output every time, we can set the seed to time.time() -- the epoch time we get from the clock. (So you can use random.seed(time.time())).

Let's now write our own random module. We'll name it myrandom, and we'll write it so that we can use it just like random:

In [8]:
# myrandom.py

def myrandom():
    global x
    x = (a*x+b) % m
    return x/m


def seed(s):
    global x
    x = (a*x+b) % m

def initialize():
    global a, b, n, x
    a = 1664525
    b = 1013904223
    m = 2**32 - 1
    x = 1
    
initialize() # call initialize outside the main block so that the seed as well as the constants are set

We can now use this code in another file:

import myrandom
import time

if __name__ == '__main__':
    # Will print the same sequence every time:
    myrandom.seed(0)
    print(myrandom.myrandom())
    print(myrandom.myrandom())
    print(myrandom.myrandom())

    # The same sequence as above again
    myrandom.seed(0)
    print(myrandom.myrandom())
    print(myrandom.myrandom())
    print(myrandom.myrandom())


    # A different sequence every run, since we are seeding using time.time()
    myrandom.seed(int(time.time())
    print(myrandom.myrandom())
    print(myrandom.myrandom())
    print(myrandom.myrandom())