主题:--- rand() --- 到底是否是绝对的随机?
琅拿度
[专家分:2820] 发布于 2009-07-27 11:36:00
程序用到了RAND(),但老感觉得到的结果不是真正的随机。
我想得到0-1间两位随机数,程序多个地方都使用了rand(),没有使用参数。
哪位大虾可以给些经验?
回复列表 (共26个回复)
11 楼
琅拿度 [专家分:2820] 发布于 2009-07-28 17:08:00
依目前经验看:短时间太频繁(如三四个语句的几个循环内)使用rand(-1)也不是好事,会造成概率值太接近甚至相等,不一定对,只是感觉。
所以目前可以尝试的办法是,在数量大的循环内,当循环达到一定数量时,才使用一次RAND(-1),并且可以让时间随机(随机长度,不要是整数,结核RAND(-1)、/3这样的能造成结果不规律的表达式去计算)停顿一阵,这样数值应该会随机平均一些。
12 楼
moz [专家分:37620] 发布于 2009-08-02 07:30:00
原来C罗是第三个人,明白了。
rand( )的参数是负数的时候,会利用系统时间做种子来获得一个随机序列,
其实序列都已经设置好了,(好比是已经固定了某个数组了)
后面的就可以使用参数(相当于数组下标)来读取随机数了。
只要种子相同,得到的随机序列是相同的。
也就是说,万一两次运行的时间是一模一样的(精确到百分之一秒),
得到的结果也会是相同的。
这样的机会微乎其微,所以没有必要多次使用rand(-1)
也可以打乱序列的顺序,来达到更乱的目的。
13 楼
琅拿度 [专家分:2820] 发布于 2009-08-03 10:36:00
既然都是计算出来的,那岂不是任何一种语言也无法做到随机?
加一个循环去打乱时间和顺序:
FOR i=1 to x
IF mod (i,37)=1
FOR k=1 to 999999+int(999999*rand(-1))
rand()
ENDFOR
ENDI
ENDFOR
14 楼
moz [专家分:37620] 发布于 2009-08-03 20:34:00
这个随机,不是你心目中的随机,但它确实可以成为现实中的随机.
当你不了解它的时候,你可以认为它是随机的,这种看法并没有错误.
你认为它不随机,是因为你太了解它了.
其实,没有必要心有芥蒂.
你要相信.
15 楼
Ilikefox [专家分:5770] 发布于 2009-08-04 08:35:00
琅拿度钻牛角尖了,呵呵。
16 楼
琅拿度 [专家分:2820] 发布于 2009-08-05 14:10:00
谢谢各位,只能尽量打乱,抽取一个算了。
17 楼
CCB2000 [专家分:690] 发布于 2009-08-14 06:15:00
一般在程序初始化时用RAND(-1)获得随机数种子。
如果在程序中多次使用RAND(-1),种子碰撞(相同)的机会增大了,随机性反而更小了。
18 楼
hsw8208 [专家分:20] 发布于 2009-09-22 15:18:00
[quote]你的感觉很对,呵呵,本来就没有产生真正随机数的函数,换句话说,RAND()是伪随机数。
早年学习FORTRAN语言(专门用于科学计算的语言),一个经典的程序就是编写产生伪随机数的函数。原理是先自行确定一个0到1之间任意的数X0(称为“种子”),然后拿它进行一番数学运算(这里把这一番数学运算称为一个随机算法),得到一个新的在0到1之间的数X1,这个X1作为产生的随机数。要得到下一个随机数,拿这个产生的随机数X1再次经过随机算法,又得到一个新的数X2,以此类推。随机算法保证每次计算结果尽可能平均分布在0到1之间。于是我们就有了得到随机数的函数,当然了,如果种子不变,得到的随机数系列必然是一致的,因此称它是伪随机。伪随机数算法有兴趣的话可在网上找到,并不难。Fox中的RAND()函数道理一样(注意,俺是说道理一样,即Fox实现的可能更复杂些,比如他的种子并不限定在0到1之间)。
当我们第一次执行RAND()的时候,如果不用参数(这参数就是种子),Fox用一个默认的种子100001得到第一个结果,后面再用RAND(),就拿第一个结果进行计算得到第二个结果,以此类推。从刚才的话,你可以推论出Fox会记住每次得到的结果,并用于下一次计算。由于默认种子是固定的,所以随机序列也是固定的,呵呵,伪随机。
做实验验证:命令窗口输入如下命令,全选中回车执行
FOR i=1 TO 5
?RAND()
ENDFOR
主窗口显示产生的5个随机数(由种子100001产生的随机数系列的前5个),记住它。
退出Fox重新启动,再次执行上述命令,注意到产生的还是那5个数。
可能的疑问是:我能不能不退出Fox,再次执行上述命令?
答:可以,不过它将按照第一次执行后的结果继续这个随机系列,固定种子产生的固定系列在同一个Session(简单的说就是fox的一次启动直到退出)中保持下去。
知道了这个原理,就能解释你为什么感觉不是真正的随机。
要做到“真正的随机”,我们应该使用不同的种子即可达到这种效果。(俺加了引号,种子本身就不是随机产生的,是指定的,所以严格的说随机数系列还是伪的,不过已经能接近达到真正随机的效果)
习惯上在使用RAND()函数之前,经常执行一句:
=RAND(-1)
把-1作为参数,并不是拿-1做种子,Fox会利用系统时间产生一个数做为种子,我们不清楚具体Fox是怎么得到这个数(种子)的,但可以知道不同时刻,得到的数必然不同。注意这个句子是无变量赋值语句,即,把RAND(-1)得到的第一个随机数丢弃,目的主要是获取种子,保证后面用RAND()得到新随机数序列。
做实验验证:命令窗口输入如下命令,全选中回车执行
=RAND(-1)
FOR i=1 TO 5
?RAND()
ENDFOR
主窗口显示产生的5个随机数
接下来不管是继续执行一遍还是退出Fox重启再次执行,你都会得到不同的随机数,呵呵,原因很简单,每次种子都变化了。
当然你也可以指定种子,比如Rand(9),拿9做种子,这样种子固定,并不好。
下面来个有趣的实验:
FOR i=1 TO 5
?RAND(-1)
ENDFOR
看起来每次都用新种子,应该得到不同的随机数,呵呵,NO。为什么?想想看。
再来一个:
FOR i=1 TO 5
?RAND(i)
ENDFOR
这回5个数不同,不过却失去了随机数的意义。为什么?想想看。
[/quote]
Ilikefox老师,继续讲下去啊,学习了!!!正研究学习这个函数!
19 楼
琅拿度 [专家分:2820] 发布于 2011-10-23 11:14:00
为了增强效果,我考虑加入:
Sleep(int(10*(rand())))
因为这个命令本身就延时不准确,再结合时间来取种,应该效果会好一点
20 楼
moz [专家分:37620] 发布于 2011-10-23 16:07:00
既然是随机,好像没有必要过于在乎它们之间的规律。
不太清楚你想把它应用在哪个方面,网上绝大部份人编这些关于随机数的,都想利用它来为自己的投注出一分力,就像人们看马报寻玄机一样,既然都是命运的偶然,哪来费那么工夫的必要。
你可能是需要在同一时刻里,获得几个不同的随机数,但却又担心它们之间会存在着某种联系,而造成不随机。
(是不是可以打个比如:想请几个人来做财务工作,却担心他们彼此认识互相勾结。)
你还去统计了它们的大小变化规律,也许是在产生随机数的过程中,为了看起来更“随机”一点,前面出了个数比较大的,后面就跟个比较小的数,你是担心会出这样的问题吧?那就打破这个顺序的规则就解决了。
用以下方法同时产生两个随机数,你是不是还能找得到它们之间的相对关系呢?
又或者,你有没有办法把电脑调到同一时刻去获得相同的序列呢?
?RAND(-1)
?RAND(MOD(SECONDS()*1000,100)*LOG(DATE()-{^1901-01-01})*100+DOW(DATE()))
?RAND(100*abs(cos(360*rand(SECONDS()*53789))))
其实更简单一些:
?rand(100*rand(100*rand(100*rand(.......
我来回复