作者meto000 (阳货欲见孔子)
看板Visual_Basic
标题Re: [VB6 ] 乱数真的够乱吗?
时间Thu Jun 25 23:53:13 2009
: → MOONRAKER:简单虚拟乱数产生器大多是 XOR + Shift 06/25 03:21
: → MOONRAKER:或者最多是 R(n) = ( R(n-1) * K ) mod M 这种形式 06/25 04:45
: → MOONRAKER:你得出rnd()的bias可能是因为浮点进位的误差所致 06/25 04:46
: → MOONRAKER:但我认为你可以自己写一个输出整数的乱数产生器 06/25 04:46
: → MOONRAKER:简单的可以找超有名的numerical recipes系列来看 06/25 04:47
关於乱数产生公式的部份
我有爬过一些文章
目前最常见的公式就是MOONRAKER大所提的 R(n) = R(n-1) * K mod M
这样会得到 0 < R < M 的整数
然後再设 Rnd = R / M
就可以得到 0 < Rnd < 1 的均匀分布乱数了
为了使周期变长以免太快出现重复
M 通常是取很大的质数
而最常被采用的则是 M = 2^31 - 1
其公式为:
R(n) = R(n-1) * 397204094 mod ( 2^31 - 1 )
Rnd = R(n) / ( 2^31 - 1 )
目前已知 SAS 就是用这个公式
至於 VB 用的是什麽就不知道了
我有尝试自己套这个公式
但这个数字实在太大了
执行下去就给我出现 Overflow
不知各位先进有没有什麽办法解决把它实作出来?
因为上面的公式没法执行
我改用Wichmann and Hill(1982)提出的另一个改进公式
Xi = 171 Xi-1 mod 30269
Yi = 172 Yi-1 mod 30307
Zi = 170 Zi-1 mod 30323
┌ Xi Yi Zi ┐
Ui = │ ----- + ----- + ----- │ mod 1 (就是去除整数只留小数部分)
└ 30269 30307 30323 ┘
此法使用了3个公式进行合并,
最後也得到服从均匀分布U(0,1)的乱数
由於个别公式所用的除数并不大(相对於前面所用的2^31–1而言),
因此计算时速度并不会减缓太多,
但循环周期却可扩大到 6.95x10^12,
比 2^31≒ 2x10^9 大概延长了3500倍
不过
当我利用这样所产生的乱数来进行测试
结果也没有比原来的 Rnd 收敛得比较漂亮
(其实是比较差啦,猜想是因为计算过程有浮点进位的问题出现)
所以
目前 VB 所提供的 Rnd 指令
应该还是最方便好用的乱数产生公式
不过
如果 VB 也是采用跟 SAS 一样的那个公式的话
当你的Case有需要产生非常大量(超过20亿个)乱数时
为避免周期循环的状况出现
可能就有需要改用那个Wichmann and Hill(1982)公式了
但一般的用途应该是都OK的啦
以上报告完毕
--
Whoever find this, I LOVE YOU!
my blog:
http://tw.myblog.yahoo.com/meto_000/
这是我的网路笔记簿,也希望与有缘看到的朋友分享
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 218.173.238.200
1F:推 journeyman:赞 06/26 10:23