以下代码片段取自伪随机数生成器(在ActionScript 3中编写):
public function random():Number {
_currentSeed = (_currentSeed * 16807) % 2147483647);
return (_currentSeed/0x7FFFFFFF) + 0.000000000233;
}
代码的第一行很容易理解,它是一个标准的线性同余生成器,乘数为16807
。第二行第一部分将结果整数转换为大致介于0
和1
之间的浮点数。
然而,第二行最后一部分+ 0.000000000233
的目的是什么?在这样的RNG中这是必要的,还是有不同的目的?
如果您查看公式的其余部分,您将看到_currentSeed
的值为0
总是会导致0
的值相同。添加(0.5/0x7fffffff)
,可以防止它在0
上卡住,但也足够小,可以防止它返回值>= 1
。
公平地说,这段代码是我6年前写的,所以我可能记错了,但我相当确定这就是原因。
算法的主体是一个著名的素数模乘线性同余生成器。所有这些前缀形容词都意味着它实现了最大的周期长度,而不像广义lcg那样有附加的术语,所以pmmlcg在20世纪50年代就很流行,因为每次调用可以减少一次操作。您永远不应该将_currentSeed
初始化为零,并且如果正确实现和播种,该算法被设计为永远不会产生零或负数,因为它基于整数算术,这是精确的。(正确的实现意味着确保结果不受整数溢出的影响。Linus Schrage早在1959年就用FORTRAN编写了一个可移植的算法,附带了一个简单的测试,包含了1000次迭代后的种子值应该是多少。
魔术数字比(1/2) / 0x7fffffff
稍大,所以它不应该将返回值推到1以上。因为它没有被添加到_currentSeed
中,所以它在避免当_currentSeed
被设置为零时可能发生的定点行为方面没有任何作用。老实说,我看不出它有什么用。
我认为,出于某种原因,_currentSeed
可能是一个负值,因为_currentSeed
是一个有符号整数。在值中添加0.000000000233
(0.5/0x7fffffff
)可以避免这种情况。