我正在编写一个在 Delphi(必须是 Delphi)中编写统计测试的程序,我听说 Random 功能有些奇怪。您必须在程序启动时调用 randomize 来随机化 random 函数的种子。
我想知道随机函数(在调用 randomize 之后)是否足够随机以进行统计测试,或者是否需要 Mersenne twister?有没有人对随机的实际实现有任何见解,可以告诉我这有多重要?
我正在编写一个在 Delphi(必须是 Delphi)中编写统计测试的程序,我听说 Random 功能有些奇怪。您必须在程序启动时调用 randomize 来随机化 random 函数的种子。
我想知道随机函数(在调用 randomize 之后)是否足够随机以进行统计测试,或者是否需要 Mersenne twister?有没有人对随机的实际实现有任何见解,可以告诉我这有多重要?
与几乎所有编程语言 RTL PRNG 一样,Delphi 的 PRNG 是一个线性同余生成器。
对于大多数小规模的事情来说它已经足够好了,但有些事情需要注意。特别要注意低位:乘法和加法的模式意味着低位根本不是很随机。但这通常仅适用于拉出然后截断mod
或类似的大 32 位值。在内部使用Random(10)
0 到 9 之间的取值时使用的是整个 32 位范围内的乘法运算,而不是mod
运算。
我无法抗拒。
如果您正在寻找一种以最快的执行时间保证随机数唯一性的方法,About.com已经在Fastest Unique Random Number Generator上发起了挑战,Patrick van Logchem 的实现被选为获胜者。
对于您的统计测试是否Random
足够可靠将取决于您打算使用它的环境。
话虽如此,我已经编写了几段需要进行适当统计的 Delphi 代码,并已用于Random
例如获取各种空分布、数据伪复制和重采样。到目前为止,我在自己的代码中还没有遇到任何Random
会产生有偏差或不可靠结果的情况,或者会妨碍其用于预期统计测试的结果。但适用于我的代码的内容不一定适用于您的代码。
如果有疑问,您当然可以对调用的结果进行统计分析Random
(例如在 R、SPSS 等中),并检查结果的分布是否违反特定统计测试的分布要求。[如果你是一名合格的科学家,无论如何这都是你应该做的。]
如果您需要其他 PRNG - 例如TPMath库包含一些。(对于更多涉及的事情,还可以选择通过 Delphi 从 R 调用精细的统计函数。)
除非您购买一些相对深奥的硬件,否则计算机可以提供的随机数的最佳近似值是完全确定的伪随机序列。一般来说,randomize 函数使用一些相对随机的值(通常基于时间,但有时基于鼠标移动 - 我不知道 Delphi 做了什么)作为提供伪随机序列入口点的种子。如果没有这个,您最终将每次都以相同的顺序返回同一组随机数,这往往会破坏首先使用随机数的目的。
好的,我意识到这并不能回答关于可靠性的问题,但它应该让你有信心要求你调用 randomize 是一个好的生成器的标志,而不是一个坏的生成器。有一堆统计测试可以显示数字序列的随机性,Delphi 随机数生成器很可能适用于多种用途,因为它是一个成熟的产品。
只是为了增加可能性 - Windows 提供了一系列内置的密码学功能。如果默认情况下还没有包含它们,那么它们可能也有一个 Delphi 包装器。
在这些功能中还有一个加密性强的随机数生成器。这是迄今为止您在软件中获得的最佳随机性,因为它会根据一长串因素自行播种。我不确定,但我怀疑它甚至会使用硬件随机数生成器,如果你有的话。
如果这还不够,您还可以尝试在Quantum Random Bit Generator Service 注册一些真正随机的值。
从 Embarcadero 网站:
_lrand 是长随机数生成器函数。_rand 使用周期为 2^64 的乘法同余随机数生成器返回 0 到 2^31 - 1 范围内的连续伪随机数。
通过使用参数值为 1 调用 srand 来重新初始化生成器。可以通过使用给定的种子编号调用 srand 来将其设置为新的起点。
如果他们在我分析后没有更改实现(Delphi 4 IIRC),那么 Delphi PRNG 的实现方式如下:
Randseed:=int32(Randseed*$08088405)+1
result:=Randseed*Range shr 32
(伪代码/假设乘法是任意大的整数)
返回 0..9 之间的随机数
StrToInt(copy(FloatToStr(Random),4,1))
注意:使用前检查 FloatToStr(Random) 长度或使用小数部分中的任何其他数字...