Python Random Function without using random module

后端 未结 6 1171
渐次进展
渐次进展 2021-02-09 17:14

I need to write the function -

random_number(minimum,maximum)

Without using the random module and I did this:

import time

def         


        
6条回答
  •  耶瑟儿~
    2021-02-09 18:01

    The thing is I need to do something that somehow uses the time

    You could generate randomness based on a clock drift:

    import struct
    import time
    
    def lastbit(f):
        return struct.pack('!f', f)[-1] & 1
    
    def getrandbits(k):
        "Return k random bits using a relative drift of two clocks."
        # assume time.sleep() and time.clock() use different clocks
        # though it might work even if they use the same clock
        #XXX it does not produce "good" random bits, see below for details
        result = 0
        for _ in range(k):
            time.sleep(0)
            result <<= 1
            result |= lastbit(time.clock())
        return result
    

    Once you have getrandbits(k), it is straigforward to get a random integer in range [a, b], including both end points. Based on CPython Lib/random.py:

    def randint(a, b):
        "Return random integer in range [a, b], including both end points."
        return a + randbelow(b - a + 1)
    
    def randbelow(n):
        "Return a random int in the range [0,n).  Raises ValueError if n<=0."
        # from Lib/random.py
        if n <= 0:
           raise ValueError
        k = n.bit_length()  # don't use (n-1) here because n can be 1
        r = getrandbits(k)          # 0 <= r < 2**k
        while r >= n: # avoid skew
            r = getrandbits(k)
        return r
    

    Example, to generate 20 random numbers from 10 to 110 including:

    print(*[randint(10, 110) for _ in range(20)])
    

    Output:

    11 76 66 58 107 102 73 81 16 58 43 107 108 98 17 58 18 107 107 77
    

    If getrandbits(k) returns k random bits then randint(a, b) should work as is (no skew due to modulo, etc).

    To test the quality of getrandbits(k), dieharder utility could be used:

    $ python3 random-from-time.py | dieharder -a -g 200
    

    where random-from-time.py generates infinite (random) binary stream:

    #!/usr/bin/env python3
    
    def write_random_binary_stream(write):
        while True:
            write(getrandbits(32).to_bytes(4, 'big'))
    
    if __name__ == "__main__":
        import sys
        write_random_binary_stream(sys.stdout.buffer.write)
    

    where getrandbits(k) is defined above.


    The above assumes that you are not allowed to use os.urandom() or ssl.RAND_bytes(), or some known PRNG algorithm such as Mersenne Twister to implement getrandbits(k).


    getrandbits(n) implemented using "time.sleep() + time.clock()" fails dieharder tests (too many to be a coincidence).

    The idea is still sound: a clock drift may be used as a source of randomness (entropy) but you can't use it directly (the distribution is not uniform and/or some bits are dependent); the bits could be passed as a seed to a PRNG that accepts an arbitrary entropy source instead. See "Mixing" section.

提交回复
热议问题