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

时间:2012-01-26 18:56:12

标签: python random cpython

我想要一个可以生成伪随机值序列的函数,但是每次运行时该序列都是可重复的。我想要的数据必须在给定范围内相当随机地分布,它不一定是完美的。

我想编写一些基于随机数据运行性能测试的代码。我希望每台机器上的每次测试运行都能保证数据相同,但我不希望出于存储原因而将测试随机数据发送出去(最终可能会有很多兆字节)。

random模块的库似乎并不是说同一种子在任何机器上都会提供相同的序列。

编辑:如果您打算建议我播种数据(如上所述),请提供说明该方法有效的文档,并将适用于一系列机器/实现。

编辑:Mac OS X上的CPython 2.7.1和PyPy 1.7以及CPython 2.7.1和CPython 2.52 = .2 Ubuntu似乎给出了相同的结果。尽管如此,没有哪个文档以黑白方式规定这一点。

有什么想法吗?

8 个答案:

答案 0 :(得分:21)

为此,我使用了重复的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之间的整数。

答案 1 :(得分:10)

存在平台差异,因此如果您在不同平台之间移动代码,我会选择DrRobotNinja描述的方法。

请查看以下示例。我桌面计算机上的Python(带有Core i7的64位Ubuntu,Python 2.7.3)给出了以下内容:

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

但如果我在我的Raspberry Pi(ARM11上的Raspbian)上运行相同的代码,我会得到一个不同的结果(对于相同版本的Python)

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

答案 2 :(得分:7)

为随机数生成器指定种子。如果你提供相同的种子,你的随机数也应该相同。

http://docs.python.org/library/random.html#random.seed

答案 3 :(得分:6)

同样可以回答为什么来自this answer的示例确实在不同的机器上产生不同的输出:

这是因为当播种随机发生器时,种子必须是整数。如果使用某个非整数对生成器进行种子处理,则必须先对其进行哈希处理。哈希函数自己不是平台独立的(显然至少不是所有这些,如果你知道更多,请纠正我。)

所以要把它们全部组合在一起:Python使用伪随机数生成器。因此,当从相同状态开始时,所产生的随机数序列将始终相同,与平台无关。它只是一种确定性的算法,没有来自外界的进一步输入。

这意味着:只要您使用相同的状态初始化随机生成器,它将生成相同的数字序列。可以使用相同的整数种子或通过保存并重新应用旧状态(random.getstate()和random.setstate())来获得相同的状态。

答案 4 :(得分:5)

使用random.seed(...)您可以生成可重复的序列。演示:

import random

random.seed(321)
list1 = [random.randint(1,10) for x in range(5)]

random.seed(321)
list2 = [random.randint(1,10) for x in range(5)]

assert(list1==list2)

这是因为random.seed(...)不是真正随机的:它是伪随机的,通过置换一些状态机产生连续的数字,给定一个初始起始条件,即“种子”。

答案 5 :(得分:5)

文档没有明确说明提供种子将始终保证相同的结果,但这可以通过Python基于所使用的算法实现随机来保证。

根据文档,Python使用Mersenne Twister作为核心生成器。一旦这个算法被播种,它就不会得到任何会改变后续调用的外部输出,所以给它相同的种子,你得到相同的结果。

当然,您也可以通过设置种子并生成大量随机数并验证它们是否相同来观察到这一点,但我理解不想单独信任它。

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

答案 6 :(得分:5)

如果随机数的质量不如跨平台的可重复性那么重要,您可以使用传统的linear congruential generators之一:

class lcg(object):
    def __init__( self, seed=1 ):
        self.state = seed

    def random(self):
        self.state = (self.state * 1103515245 + 12345) & 0x7FFFFFFF
        return self.state

由于这是使用整数运算在程序中编码的,因此它应该在任何合理的平台上具有确定性的可重复性。

答案 7 :(得分:1)

我刚刚尝试了以下内容:

import random
random.seed(1)
random.random()
random.random()
random.random()

random.seed(1)
random.random()
random.random()
random.random()

我以不同的速度多次在CLI中输入每一行。每次都产生相同的值。