代码之家  ›  专栏  ›  技术社区  ›  Peter Smit

如何在python中使用random.jumpahead

  •  3
  • Peter Smit  · 技术社区  · 14 年前

    我有一个应用程序做了1000次特定的实验(多线程,这样就可以同时做多个实验)。每一个实验都需要批准。50000个random.random()调用。

    什么是最好的方法来得到这种真正的随机性。我可以复制一个随机对象到每一个实验中,并做一个超过50000*expid的跳跃。文档表明,Jumpahead(1)已经扰乱了状态,但这真的是真的吗?

    或者有没有其他方法可以用“最好的方法”来做到这一点?

    (不,随机数不是用于安全,而是用于metropolis hasting算法。唯一的要求是实验是独立的,而不是随机序列是否是可预测的。

    4 回复  |  直到 13 年前
        1
  •  3
  •   Charles Brunet    13 年前

    你不应该用那个函数。没有证据表明它能在梅森捻线机上工作。事实上,它是 removed from Python 3 for that reason .

    有关在并行环境中生成伪随机数的详细信息,请参见 this article from David Hill .

        2
  •  5
  •   S.Lott    14 年前

    我可以复制一个随机对象到每一个实验中,并做一个超过50000*expid的跳跃。

    大致正确。每根线都有自己的 Random 实例。

    所有这些种子的种子价值相同。使用常量进行测试,在“为记录运行”时使用/dev/random。

    编辑 . 在python外部和较旧的实现中,使用 jumpahead( 50000 * expid ) 以避免两台发电机以并行的值序列结束的情况。在任何合理的当前(2.3之后)python中, jumpahead 不再是线性的 expid 足以扰乱国家秩序。

    你不能就这么做 jumpahead(1) 在每个线程中,因为这将确保它们是同步的。使用 jumpahead( expid ) 以确保每个线程都有明显的混乱。

    文档表明,Jumpahead(1)已经扰乱了状态,但这真的是真的吗?

    是的,跳跃前进确实“扰乱”了国家。回想一下,对于一个给定的种子,你会得到一个——长——但是 固定的 伪随机数序列。你在这个序列中领先。要通过随机性测试,必须从中获取所有值 序列。

    编辑 . 从前,跳跃前进(1)是有限的。现在,向前跳跃(1)真的会造成更大的混乱。然而,加扰是确定的。你不能就这么做 (1) 每一根线。

    如果你有多个不同种子的生成器,你违反了“一个种子有一个序列”的假设,你的数字就不会像从一个序列得到的那样随机。

    如果你只跳1,你可能会得到并行序列,这可能是相似的。[这种相似性可能无法察觉; 理论上 ,有相似之处。】

    当你跳到50000,你保证你遵循1-序列-1-种子前提。你还保证在两个实验中不会有相邻的数字序列。

    最后,你也有重复性。对于给定的种子,结果是一致的。

    同样的跳跃:不好。

    >>> y=random.Random( 1 )
    >>> z=random.Random( 1 )
    >>> y.jumpahead(1)
    >>> z.jumpahead(1)
    >>> [ y.random() for i in range(5) ]
    [0.99510321786951772, 0.92436920169905545, 0.21932404923057958, 0.20867489035315723, 0.91525579001682567]
    >>> [ z.random() for i in range(5) ]
    [0.99510321786951772, 0.92436920169905545, 0.21932404923057958, 0.20867489035315723, 0.91525579001682567]
    
        3
  •  3
  •   Alex Martelli    14 年前

    jumpahead(1) 确实足够(和 jumpahead(50000) 或任何其他此类调用,在当前的 random --我相信这与基于mersenne twister的实现同时出现。因此,使用任何符合程序逻辑的参数。(请使用单独的 random.Random 当然,出于线程安全的目的,每个线程都有一个实例,正如您的问题已经暗示的那样)。

    ( 随机的 模块生成的数字并不意味着加密性很强,因此不用于安全目的是一件好事;-)。

        4
  •  0
  •   Will Robinson    14 年前

    每个 random module docs 在python.org:

    “您可以实例化自己的随机实例,以获取不共享状态的生成器。”

    正如你所提到的,还有一个相关的跳转注意事项。但那里的保证有点模糊。如果对操作系统随机性的调用并没有昂贵到支配你的运行时间,我会跳过所有的微妙之处,做一些类似的事情:

    randoms = [random.Random(os.urandom(4)) for _ in range(num_expts)]
    

    如果num_expts是~1000,那么你的种子中不太可能有任何碰撞(birthday paradox说,在碰撞概率达到50%之前,你需要大约65000个实验)。如果这对你来说还不够好,或者如果实验的次数是100k而不是1k,那么我认为这是合理的

    for idx, r in enumerate(randoms):
      r.jumpahead(idx)
    

    请注意,我认为仅仅使种子更长是行不通的(例如os.urandom(8)),因为随机文档声明种子必须是散列的,所以在32位平台上,您最多只能在种子中获得32位(4字节)的有用熵。

    这个问题激起了我的好奇心,所以我去看了看 code 实现随机模块。我绝对不是一个prng专家,但它确实看起来稍微不同的n值在跨接(n)将导致明显不同的随机实例状态。(总是害怕反驳亚历克斯·马泰利,但是密码 随机状态乱序时使用n的值)。