Skip to main content
 首页 » 编程设计

不使用随机模块的Python随机函数

2025年05月04日14jyk

我需要编写函数 -

random_number(minimum,maximum) 

在不使用随机模块的情况下,我这样做了:

import time 
 
def random_number(minimum,maximum): 
    now = str(time.clock()) 
    rnd = float(now[::-1][:3:])/1000 
    return minimum + rnd*(maximum-minimum) 

我不确定这是否合适..是否有一种已知的方法可以节省时间?

请您参考如下方法:

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

您可以根据 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 

一旦您有了 getrandbits(k),就可以直接获得范围 [a, b] 内的随机整数,包括两个端点。 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 

例如,生成 20 个从 10 到 110 的随机数,包括:

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

输出:

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

如果 getrandbits(k) 返回 k 随机位,则 randint(a, b) 应该按原样工作(没有因模而产生的偏差等)。

测试getrandbits(k)的质量,dieharder可以使用实用程序:

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

其中 random-from-time.py 生成无限(随机)二进制流:

#!/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) 

上面定义了 getrandbits(k)。


以上假定您不允许使用 os.urandom() 或 ssl.RAND_bytes(),或一些已知的 PRNG 算法,例如 Mersenne Twister实现 getrandbits(k)。


getrandbits(n) 使用“time.sleep() + time.clock()”实现失败 dieharder 测试(太多不是巧合)。

这个想法仍然合理:时钟漂移可以用作随机性(熵)的来源,但您不能直接使用它(分布不均匀和/或某些位是相关的);这些位可以作为种子传递给接受任意熵源的 PRNG。参见 "Mixing" section .