在尝试解决this question时,我写了以下内容,以尝试实现Box-Muller transform以在纯VBA中生成随机正态变量:
Function RandNorm(Optional mean As Double = 0, Optional sd As Double = 1) As Double
Dim s As Double
s = Sqr(-2 * Log(Rnd())) * Cos(6.283185307 * Rnd()) '6.28 etc. is 2*pi
RandNorm = mean + sd * s
End Function
以下比较弱的测试始终有效,返回接近0的数字:
Sub test1()
Randomize
Dim s As Double
Dim i As Long
For i = 1 To 17000000
s = s + RandNorm()
Next i
Debug.Print s / 17000000
End Sub
另一方面,以下测试从不起作用(因为它尝试获取对数0(未定义):
Sub test2()
Randomize
Dim s As Double
Dim i As Long
Debug.Print Rnd() 'just to clock it
For i = 1 To 17000000
s = s + RandNorm()
Next i
Debug.Print s / 17000000
End Sub
问题在于,每2 ^ 24次调用(平均少于17,000,000次),rnd()
平均会返回0
。调整RandNorm
的定义以避开零当然很容易(请参阅链接到问题),但是上面的代码仍然让我感到困惑。如果每个测试在一半时间(当零被送入Log()
中)失败并且在一半时间(当零被送入Cos()
中时工作)对我来说是完全合理的。似乎Randomize避免了至少一半的可能种子。
为什么随机化会以这种方式表现?有没有一种方法可以为随机数生成器提供种子,以使随机数生成器的所有可能状态都可以发生?
编辑时
如果我定义以下子项:
Sub ReRandomize()
Dim r As Double
Randomize
If Rnd() > 0.5 Then r = Rnd()
End Sub
并修改上面的test1
和test2
以使用ReRandomize
而不是Randomize
,两个测试子都将在50%的时间内失败,因此 可能会回答有关是否存在“为随机数生成器提供种子以使随机数生成器的所有可能状态都可以发生的方法”的部分问题?关于Randomize
为何以其行为方式仍然是个谜。这是Excel VBA问题第二次使我意识到Randomize is a weird sub。对于rnd()
的典型用法而言,这些都无关紧要,但确实强调了它是一种质量较低的随机数生成器,不应用于认真的统计工作。
答案 0 :(得分:0)
我只是将Rnd calc修改为不包含0或1。您必须记住,Rnd Function可以产生0或1范围内的数字(双精度类型)。因此,可能会有重复的数字很低。
dbl1stRnd = Rnd()
dblRnd = (0.9999 - 0.0001) * dbl1stRnd + 0.0001
s = Sqr(-2 * Log(dblRnd)) * Cos(6.283185307 * dblRnd) '6.28 etc. is 2*pi
带有Randomize的常规Rnd()函数的一些示例输出:
3.633606E-02
0.2324036
0.3460443
0.5870923
5.553758E-02
0.2629338
0.2400494
0.1982901
0.5923058
0.7915452
0.4874671
0.2062811
0.5676001
0.1178594
1.932621E-03
0.4326598
0.8291379
我希望这能解释一些并且是您想要的。