我如何在两个方向上制作LCG(伪随机数发生器类型)?
我知道前进是(a*x+c)%m
,但我怎么能扭转呢?
我正在使用这个,所以我可以将种子存储在地图中玩家的位置,并且能够通过在LCG中向后和向前传播来生成周围的东西(如某种随机数字线)。
答案 0 :(得分:3)
所有LCG循环。在实现最大循环长度的LCG中,每个值x都有一个唯一的前驱和唯一的后继(对于没有达到最大循环长度的LCG,或者对于具有子循环行为的其他算法,例如von,它不一定适用)诺伊曼的middle-square method)。
假设我们的LCG具有周期长度L.由于行为是循环的,这意味着在L次迭代之后我们回到起始值。通过向后退一步找到前任值在数学上等同于向前迈出(L-1)步。
最大的问题是,这是否可以转化为一个步骤。如果您正在使用Prime Modulus Multiplicative LCG(其中添加常数为零),那么事实证明这很容易。如果x i + 1 = a * x i %m,那么x i + n = a n * x i %m。作为具体示例,考虑PMMLCG,其中a = 16807且m = 2 31 -1。它的最大循环长度为m-1(由于显而易见的原因,它永远不会产生0),因此我们的目标是迭代m-2次。我们可以使用容易获得的指数/ mod库预先计算 m-2 %m = 1407677000。因此,发现前向步骤为x i + 1 = 16807 * x i %2 31 -1,同时发现向后步骤如x i-1 = 1407677000 * x i %2 31 -1。
其他强>
通过以矩阵形式转换并进行快速矩阵求幂以提出等效的单级变换,可以将相同的概念扩展到通用的全周期LCG。 x i + 1 =(a * x i + c)%m的矩阵公式为X i + 1 = T·X < sub> i %m,其中T是矩阵[[a c],[0 1]]
,X是转置的列向量(x,1)。通过使用平方和减半功率的快速取幂技术将T提高到任何所需功率,可以快速计算LCG的多次迭代。在注意到矩阵T的功率永远不会改变第二行之后,我能够专注于第一行计算并在Ruby中产生以下实现:
def power_mod(ary, mod, power)
return ary.map { |x| x % mod } if power < 2
square = [ary[0] * ary[0] % mod, (ary[0] + 1) * ary[1] % mod]
square = power_mod(square, mod, power / 2)
return square if power.even?
return [square[0] * ary[0] % mod, (square[0] * ary[1] + square[1]) % mod]
end
其中ary
是包含a和c的乘法,乘法和加法系数。
使用此设置,power
设置为周期长度-1,我能够确定产生various LCGs listed in Wikipedia的前任的系数。例如,要使用a = 1664525,c = 1013904223和m = 2 32 “反转”LCG,请使用a = 4276115653和c = 634785765.您可以轻松确认后一组系数反转使用原始系数产生的序列。