antiloquax
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
Contact: Website

random number generator

Sun Jan 20, 2013 7:54 pm

I am not very experienced in using OOP. I used it here so that I would not have to keep passing the seed around the program.

I would be grateful if anyone can tell me if I have made any silly errors here. It seems to work as I expected it to.

Code: Select all

# oop_rng.py
# Using the linear convergence method of D. H. Lehmer.
# By default, this program uses the MINST settings.
# MINST:        n = 2^31,     g = 7^5
# Forth - LC53: n = 2^32 - 5, g = 2^32 - 333333333
# Cray  - RANF: n = 2^48,     g = 44485709377909

from time import *

def main():
    rng = Rng()
    print("*** Random Numbers ***")
    print("*** D. H. Lehmer's method. ***")
    print("Enter count, start, end (separated by commas).")
    while 1:
        user = input("> ")
        try:
            c,s,e = user.split(',')
        except ValueError:
            if user == 't':
                rng.test()
                continue
            else:
                return
        for i in range(int(c)):
            print(rng.rng(int(s),int(e)), end = " ")
        print()
        
class Rng():
    def __init__(self):
        """Set modulus (n), multiplier (g) and seed."""
        self.n = self.power(2,31)
        self.g = self.power(7,5)
        self.seed = self.get_seed()
    
    def get_seed(self):
        """Uses system time to set a random seed."""
        x = int(time() * 1000) % 1000 
        return self.coprime(x+1000)

    def coprime(self, x):
        """Finds a value coprime with self.n."""
        while 1:
            if self.gcd(x, self.n) == 1:
                return x
            else:
                x += 1

    def rng(self, s, e):
        """Updates seed to get next random number."""
        self.seed = (self.g * self.seed) % self.n
        return self.get_int(s,e)

    def get_int(self, s, e):
        """Returns integer between s and e."""
        return int((self.seed / self.n) * (e-s +1)) + s
      
    def power(self, x, y):
        """"Returns x^y, for integer values of y."""
        z = 1
        while y != 0:
            if y % 2 == 0:
                x *= x
                y //= 2
            else:
                z *= x
                y -= 1
        return z

    def test(self):
        """Runs a test on 1000 random numbers and prints results."""
        print("Seed =", self.seed)
        print("Frequencies of digits 0-9 in 1000 trials:")
        freq = [0]*10
        for i in range(1000):
            freq[self.rng(0, 9)]+= 1
        
        for i,j in enumerate(freq):
            print(i, ":", j)

    def gcd(self, a, b):
        """Euclid's Algorithm."""
        while b > 0:
            a, b = b, a % b
        return a

if __name__ == "__main__":
    main()

-rst-
Posts: 1316
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland

Re: random number generator

Mon Jan 21, 2013 1:56 pm

Cannot spot any obvious mistakes - pretty good example of OOP.

Of course could nitpick about power() and coprime() being more generic functions (not specific to the random generator class and in a bigger piece of software could be used elsewhere) and should be put in a more generic 'maths' class ...and in fact there is a power operator already in Python.
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'

antiloquax
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
Contact: Website

Re: random number generator

Mon Jan 21, 2013 2:15 pm

Thanks, rst. I take your point about power() and coprime(). I appreciate you reading this.

Digital Larry
Posts: 75
Joined: Tue Jul 24, 2012 9:10 pm
Location: Silicon Valley, CA

Re: random number generator

Mon Jan 21, 2013 2:34 pm

Many years ago I needed a pseudo random number generator for 16 bit values in an 8031 based system I designed. I just experimented with different values of x and y in the very simple relationship:

next = last * x + y ( of course limited to 16 bits)

I don't recall the magical values of x and y but I was able to get a sequence that took over 20,000 iterations to repeat.

Return to “Python”