如何生成可重复的随机数序列?

21 投票
9 回答
18536 浏览
提问于 2025-04-17 11:10

我想要一个可以生成伪随机值序列的函数,但这个序列在每次运行时都要能重复。我要的数据在给定的范围内要分布得比较随机,虽然不需要完美。

我想写一些代码,并对其进行性能测试,这些测试是基于随机数据的。我希望每次测试运行时,所有机器上的数据都是一样的,但我不想因为存储原因把随机数据和测试一起打包(因为可能会占用很多兆字节)。

random模块的库似乎没有说明相同的种子在任何机器上都会产生相同的序列。

补充说明:如果你打算建议我给数据设置种子(就像我上面说的),请提供相关文档,说明这种方法是有效的,并且可以在多种机器或实现上工作。

补充说明:在Mac OS X上,CPython 2.7.1和PyPy 1.7,以及在Ubuntu上,CPython 2.7.1和CPython 2.52=.2似乎都给出了相同的结果。不过,仍然没有明确的文档说明这一点。

有什么想法吗?

9 个回答

12

不同的平台之间是有差异的,所以如果你在不同的平台上移动你的代码,我建议你使用DrRobotNinja提到的方法。

请看下面这个例子。我在我的桌面电脑上运行Python(64位的Ubuntu,配有Core i7,Python版本是2.7.3),得到的结果是:

> import random
> r = random.Random()
> r.seed("test")
> r.randint(1,100)
18

但是如果我在我的树莓派上运行相同的代码(树莓派使用的是ARM11的Raspbian系统),我会得到一个不同的结果(尽管使用的是相同版本的Python)

> import random
> r = random.Random()
> r.seed("test")
> r.randint(1,100)
34
26

为了这个目的,我使用了重复的MD5哈希,因为哈希函数的目的是在不同平台之间进行一对一的转换,所以在不同的平台上结果总是一样的。

import md5

def repeatable_random(seed):
    hash = seed
    while True:
        hash = md5.md5(hash).digest()
        for c in hash:
            yield ord(c)

def test():
    for i, v in zip(range(100), repeatable_random("SEED_GOES_HERE")):
        print v

输出:

184 207 76 134 103 171 90 41 12 142 167 107 84 89 149 131 142 43 241 211 224 157 47 59 34 233 41 219 73 37 251 194 15 253 75 145 96 80 39 179 249 202 159 83 209 225 250 7 69 218 6 118 30 4 223 205 91 10 122 203 150 202 99 38 192 105 76 100 117 19 25 131 17 60 251 77 246 242 80 163 13 138 36 213 200 135 216 173 92 32 9 122 53 250 80 128 6 139 49 94

简单来说,这段代码会把你的种子(任何有效的字符串)进行多次哈希处理,从而生成0到255之间的整数。

6

文档没有明确说明提供一个种子值是否总能保证得到相同的结果,但在Python的随机数实现中,这是有保证的,这要归功于它所使用的算法。

根据文档,Python使用的是梅森旋转算法作为核心生成器。一旦这个算法被设置了种子,它就不会受到任何外部因素的影响,这样后续的调用结果就不会改变。所以只要给它相同的种子,你一定会得到相同的结果。

当然,你也可以通过设置种子并生成一大堆随机数来观察这一点,验证它们是否相同,但我理解你可能不想仅仅依靠这个来相信。

我没有检查除了CPython之外的其他Python实现,但我非常怀疑它们会使用完全不同的算法来实现随机模块。

撰写回答