Wrt 如何正确选择生成器的数字,在 Wiki 页面中有 Hull-Dobell Theorem 的描述,它告诉您如何选择a
和c
拥有全周期生成器。您从数字食谱中获得了数字,据我所知,您将获得完整的 [0...2 32 ) 生成器。或者您可以查看本文中的品质因数,有 (a,c) 对适用于任何所需的周期大小。
关于测试,请查看@pjs 提供的论文。
when it comes to choosing seeds, I was thinking about nanoseconds, but I have no idea how to implement it and will it make sense at all? The idea is to show that the selected seeds were chosen randomly and not so much from the cap
. 我认为这不是一个好主意,因为您不能保证从 time/ceil/... 挑选的种子不会重叠。LCG 基本上是双射的 [0...2 32 )<->[0...2 32 ) 映射,并且相对容易重叠随机数流,因此您的结果是相关的。
相反,我建议使用 LCG 的另一个不错的属性 - 对数向前(和向后)跳跃。因此,对于在核心上进行模拟,N
您可以只选择单个种子并在第一个代码上运行,相同的种子但为第二个核心跳过(N/2 32),种子和跳过(N/2 32 * 2)等等。
具有显式状态和跳过的 LCG 代码如下,Win10 x64,Python 3.7 Anaconda
import numpy as np
class LCG(object):
UZERO: np.uint32 = np.uint32(0)
UONE : np.uint32 = np.uint32(1)
def __init__(self, seed: np.uint32, a: np.uint32, c: np.uint32) -> None:
self._seed: np.uint32 = np.uint32(seed)
self._a : np.uint32 = np.uint32(a)
self._c : np.uint32 = np.uint32(c)
def next(self) -> np.uint32:
self._seed = self._a * self._seed + self._c
return self._seed
def seed(self) -> np.uint32:
return self._seed
def set_seed(self, seed: np.uint32) -> np.uint32:
self._seed = seed
def skip(self, ns: np.int32) -> None:
"""
Signed argument - skip forward as well as backward
The algorithm here to determine the parameters used to skip ahead is
described in the paper F. Brown, "Random Number Generation with Arbitrary Stride,"
Trans. Am. Nucl. Soc. (Nov. 1994). This algorithm is able to skip ahead in
O(log2(N)) operations instead of O(N). It computes parameters
A and C which can then be used to find x_N = A*x_0 + C mod 2^M.
"""
nskip: np.uint32 = np.uint32(ns)
a: np.uint32 = self._a
c: np.uint32 = self._c
a_next: np.uint32 = LCG.UONE
c_next: np.uint32 = LCG.UZERO
while nskip > LCG.UZERO:
if (nskip & LCG.UONE) != LCG.UZERO:
a_next = a_next * a
c_next = c_next * a + c
c = (a + LCG.UONE) * c
a = a * a
nskip = nskip >> LCG.UONE
self._seed = a_next * self._seed + c_next
#%%
np.seterr(over='ignore')
a = np.uint32(1664525)
c = np.uint32(1013904223)
seed = np.uint32(1)
rng = LCG(seed, a, c)
print(rng.next())
print(rng.next())
print(rng.next())
rng.skip(-3) # back by 3
print(rng.next())
print(rng.next())
print(rng.next())
rng.skip(-3) # back by 3
rng.skip(2) # forward by 2
print(rng.next())
更新
生成 10k 个数字
np.seterr(over='ignore')
a = np.uint32(1664525)
c = np.uint32(1013904223)
seed = np.uint32(1)
rng = LCG(seed, a, c)
q = [rng.next() for _ in range(0, 10000)]