任何以下形式的 LCGx[n+1] = (x[n] * a + c) % m
可以非常快速地跳到任意位置。
从种子值为零开始,LCG 的前几次迭代将给出以下序列:
x₀ = 0
x₁ = c % m
x₂ = (c(a + 1)) % m
x₃ = (c(a² + a + 1)) % m
x₄ = (c(a³ + a² + a + 1)) % m
很容易看出,每一项实际上都是几何级数的总和,可以用以下公式计算:简单的公式 https://en.wikipedia.org/wiki/Geometric_series#Sum:
x_n = (c(a^{n-1} + a^{n-2} + ... + a + 1)) % m
= (c * (a^n - 1) / (a - 1)) % m
The (a^n - 1)
项可以通过以下方式快速计算模幂 https://en.wikipedia.org/wiki/Modular_exponentiation,但除以(a-1)
有点棘手,因为(a-1)
and m
都是偶数(即不互质),所以我们无法计算模乘逆 https://en.wikipedia.org/wiki/Modular_multiplicative_inverse of (a-1) mod m
直接地。
相反,计算(a^n-1) mod m*(a-1)
,然后对结果进行直接(非模块化)除法a-1
。在 Python 中,计算过程如下:
def lcg_skip(m, a, c, n):
# Calculate nth term of LCG sequence with parameters m (modulus),
# a (multiplier) and c (increment), assuming an initial seed of zero
a1 = a - 1
t = pow(a, n, m * a1) - 1
t = (t * c // a1) % m
return t
def test(nsteps):
m = 2**64
a = 6364136223846793005
c = 1442695040888963407
#
print("Calculating by brute force:")
seed = 0
for i in range(nsteps):
seed = (seed * a + c) % m
print(seed)
#
print("Calculating by fast method:")
# Calculate nth term by modular exponentiation
print(lcg_skip(m, a, c, nsteps))
test(1000000)
因此,要创建具有不重叠输出序列的 LCG,您需要做的就是使用由lcg_skip()
值为n
相距足够远。