5

指定されたステップ数だけ乱数ジェネレーターを以前の状態に「ロールバック」して、繰り返し乱数を取得することは可能ですか?

私はこのようなことをしたいです:

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

これを達成するための私の現在の唯一のアイデアは、生成されたすべての乱数をリストに格納して戻ることです。ただし、この関数はあまり使用されないので、かなり大量の乱数を生成する予定なので、個人的にはそうしない方法を好みます。

4

1 に答える 1

8

あなたは見てみたいrandom.getstate()random.setstate()。これを生成されたアイテムの数を追跡することと組み合わせると、やりたいことを行うのは非常に簡単です。

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
于 2012-12-07T16:07:12.243 に答える