作者meto000 (阳货欲见孔子)
看板Visual_Basic
标题[VB6] 乱数真的够乱吗?
时间Thu Jun 25 00:01:45 2009
大家应该都知道
用 X=Rnd 指令就可以得到一个介於0~1之间的均匀分布乱数
也就是 X~Uniform(0,1)
然而 VB 只能产生均匀分布的乱数
因此小弟最近写了个各种分布的乱数产生程式来用
但发现生出来的东西似乎不是很精确
因此进一步对 Rnd 这个指令加以检验
才发现大事不妙
理论上
由於X~Uniform(0,1)
故E(X)=1/2, Var(X)=1/12
因此
当我们反覆取n个乱数後
再计算其平均和变方
随着 n->∞
所得的平均和变方应该会趋近1/2和1/12
这也是所谓蒙地卡罗法(Monte Carlo)和拔靴法(Bootstrap)等的理论基础
在各种科学领域的应用多不胜数
最简单的蒙地卡罗法应用
大概就属在单位平面中逢机取点来估算圆周率了
这个我在高中时就玩过了
应该不需要在这边班门弄斧才对
离题了
话说现在要验证Rnd是否真的符合均匀分布
於是我写了这样的小程式加以验证:
Open "rnd.txt" For Output As #1
X1 = 0: X2 = 0: Randomize
For I = 1 To 10000000
X = Rnd
X1 = X1 + X
X2 = X2 + X ^ 2
If I Mod 100000 = 0 Then
EX = X1 / I
VarX = (X2 - EX ^ 2 * I) / I
'Print #1, I, X
Print #1, I, EX, VarX * 12
End If
Next I
Close #1
全部的变数都宣告为倍精度
这个程式基本上就是反覆取1000万个乱数
并同时累积计算 韈X 和 韈X^2
然後每隔10万个就输出一次平均EX和变方VarX*12
结果如下:
100000 0.500341235609055 0.998641767848771
200000 0.499809045362473 1.00078372215905
300000 0.500107454074224 0.998437901086435
400000 0.500276461744309 0.998385742258827
500000 0.500290068372726 0.999079838731831
600000 0.500419607292811 1.00021925961703
700000 0.50026993564742 1.00019207389547
800000 0.50015473200798 1.000139160073
900000 0.500144928914176 1.00052572698579
1000000 0.500105085889816 1.00056944920825
略
9000000 0.500131491163254 0.999874573474332
9100000 0.500137886596617 0.999861888329618
9200000 0.500145418414655 0.999857654740129
9300000 0.500141381108992 0.999838666710201
9400000 0.50014871621416 0.999868309864149
9500000 0.50014508351587 0.99988266186096
9600000 0.500142511142095 0.999940878307397
9700000 0.50014840750419 0.999973340103397
9800000 0.500148654139577 0.999944556581512
9900000 0.500138692927601 0.999910212634631
10000000 0.500136948072433 0.999931865426466
按理
所得的平均和12倍变方应该会趋近於0.5和1
然而
一开始做10万次模拟发现没有收敛(在0.49-0.51间乱跳)
做到1000万次也只收敛到小数第四位
而且是有偏歪的 0.50013-0.50014
也难怪转换出来的各种分布乱数是有问题的了
这麽一来
用VB来做模拟研究
不就有问题了吗?
那是 Rnd 指令本身有问题
还是我的程式哪边搞错了呢?
可以请大家帮忙看看吗?
请问各位先进
有人知道 VB 的 Rnd 乱数产生指令是怎麽运作的吗?
它是经由怎样的公式运算产生的呢?
不知哪边可以查得到?
恳请赐教,感激不尽
--
迷时师渡 悟时自渡
~ 六祖惠能
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 220.140.18.156
※ meto000:转录至看板 Statistics 06/25 00:08
1F:→ MOONRAKER:简单虚拟乱数产生器大多是 XOR + Shift 06/25 03:21
2F:→ MOONRAKER:或者最多是 R(n) = ( R(n-1) * K ) mod M 这种形式 06/25 04:45
3F:→ MOONRAKER:你得出rnd()的bias可能是因为浮点进位的误差所致 06/25 04:46
4F:→ MOONRAKER:但我认为你可以自己写一个输出整数的乱数产生器 06/25 04:46
5F:→ MOONRAKER:简单的可以找超有名的numerical recipes系列来看 06/25 04:47