【问题标题】:Rolling back the random number generator in python?回滚python中的随机数生成器?
【发布时间】:2012-12-07 16:06:10
【问题描述】:

是否可以通过指定数量的步骤将随机数生成器“回滚”到较早的状态以获得重复的随机数?

我希望能够做这样的事情:

print(random.random())
0.5112747213686085
print(random.random())
0.4049341374504143
print(random.random())
0.7837985890347726

random.rollback(2) #go back 2 steps

print(random.random())
0.4049341374504143
print(random.random())
0.7837985890347726

我目前唯一的想法是将所有生成的随机数存储到一个列表中以供返回。但是,我个人更喜欢不涉及这样做的方法,因为我计划生成大量随机数,而此函数不会经常使用。

【问题讨论】:

  • 您为什么要这样做?你不能用相同的种子重新播种生成器吗?
  • "将所有生成的随机数存储到一个列表中以返回。" - 一个不错的解决方案,我会坚持下去。
  • 澄清一下,我希望能够在任意点返回。据我所见, random.getstate() 和 random.setstate() 只允许我回到固定点,除非我保存每个状态(在这种情况下,我宁愿保存所有随机数) .我将随机数用作多个函数的参数,其想法是,如果用户不喜欢特定随机数给出的某个函数的结果,则用户可以使用不同的函数重做。跨度>

标签: python random


【解决方案1】:

您想看看random.getstate()random.setstate()。将此与跟踪生成的项目数量结合起来,就可以很容易地做你想做的事。

请注意,如果您依赖于此,则必须小心使用 random 的其他代码,因此我建议您创建一个 random.Random() 实例来避免这种情况。

这个模块提供的函数实际上是一个绑定的方法 random.Random 类的隐藏实例。你可以实例化你的 拥有 Random 实例以获取不共享状态的生成器。

(来自文档)

示例实现:

from itertools import islice
import collections
from random import Random

def consume(iterator, n):
    "Advance the iterator n-steps ahead. If n is none, consume entirely."
    # Use functions that consume iterators at C speed.
    if n is None:
        # feed the entire iterator into a zero-length deque
        collections.deque(iterator, maxlen=0)
    else:
        # advance to the empty slice starting at position n
        next(islice(iterator, n, n), None)

class RewindRandom:
    def __init__(self):
        self._random = Random()
        self._state = self._random.getstate()
        self._count = 0

    def __iter__(self):
        while True:
            yield self._random.random()

    def __call__(self):
        self._count += 1
        return next(iter(self))

    def rollback(self, amount):
        self._random.setstate(self._state)
        consume(self, self._count-amount)
        self._count -= amount

可以这样使用:

random = RewindRandom()

>>> random()
0.31276818768213244
>>> random()
0.7031210824422215
>>> random()
0.7196351574136909
>>> random.rollback(2)
>>> random()
0.7031210824422215
>>> random()
0.7196351574136909
>>> random()
0.6582894948982371

【讨论】:

  • 这在原则上是正确的,但请注意,随机状态比单个随机 int 大得多;因此,如果您需要能够倒带到任何位置,实际上最好保存输出,而不是状态。如果您在很长的序列中只有几个停止点,那就完美了。
  • @alexis 你只需要存储一个状态和一个数字,你存储初始状态跟踪请求的随机数的数量,然后当你想恢复时,你回到那个状态消费(itertools 有一个很好的 consume() 配方)number_of_random_numbers_used - rewind_amount 随机数到达你想要的点。
  • 我理解 OP 想要随机访问,而不是倒带和重放(长序列可能会变慢)。因此,正如我认为您所建议的那样,如果没有太多检查点,检查点中间状态似乎是正确的。
  • 目前还不清楚 OP 想要从中得到什么,如果 OP 事先知道他想返回到哪里,检查点可能是一个很好的策略。
  • 哈哈,确实很不清楚。顺便说一句,+1 用于解决随机消费者之间的共享状态。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-04
  • 1970-01-01
  • 2011-04-14
  • 1970-01-01
  • 1970-01-01
  • 2021-08-14
相关资源
最近更新 更多