Chinaunix

标题: srand+rand函数产生的数字重复率太高,为什么 [打印本页]

作者: jeanlove    时间: 2009-03-30 16:52
标题: srand+rand函数产生的数字重复率太高,为什么
我写了这么一个小程序:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
int main(void)
{
srand(time(NULL));
int r=abs(rand());
float f=r;
f/=RAND_MAX;
f*=13;
int result=(int)ceil(f);//为了产生1-13之间的随机数,代表扑克牌
printf("%d\n",result);
return 0;
}
在solaris8+CC上面编译,执行了./a.out若干次,输出的结果是:
12,6,7,13,1,7,8,1,2,8,2,3,9,10,3,10,10,4,11,4,5,11,5,12,6,12,13,6,13,1,7,1,1,2,8,9,2,3,10,4,10,,4,4,11

我发现:一个数字如果出现了,那么接下来3次运行,再次出现几率也是相当高的。我换成了g++(2.95.2)编译器,结果类似
3,9,3,10,3,4,10,4,11,4,5,5,12

这说明什么呢?srand并不能真的产生一个可靠的随机数种子?

还请dx指点!!
作者: xp5211314    时间: 2009-03-30 16:52
你的种子是根据time(NULL)函数来的, 如果你点太快的话  生产的种子基本上一样,应该会影响你产生的随机数。

按自己的经验 只要相隔一秒以上  基本不得怎么这么频繁重复
作者: evaspring    时间: 2009-03-30 16:58
没有什么真正可靠的随机数种子,这样的数字不是很随机么?

假如 产生 13个数字 1 ~13 都有了 那才不正常了呢 ~
作者: ziggler    时间: 2009-03-30 17:00
http://www.cppblog.com/pengkuny/archive/2007/05/25/15057.html

请参考
作者: hellioncu    时间: 2009-03-30 17:02
rand本身产生的就是伪随机数
作者: shan_ghost    时间: 2009-03-30 17:23
你算一算3次取得的数字都不同的概率,就知道为什么了。

http://blog.codingnow.com/2008/04/quasi-random_sequences.html
http://blog.codingnow.com/2007/11/random.html
作者: shan_ghost    时间: 2009-03-30 17:25
另外,想取一个随机序列的话,仅初始化一次随机数发生器,然后使用这个发生器依次取出全部数字,这样得到的东西的分布才符合预期。

随机数发生器可没保证不同种子产生的第一个数的随机分布。

你这样用时间当随机种子并连续取第一个数值,相当于把一系列连续数字(如 123333 123334 123335)代入随机数公式,取得的数据没有相关性才怪。

[ 本帖最后由 shan_ghost 于 2009-3-30 17:29 编辑 ]
作者: jeanlove    时间: 2009-03-30 17:27
原帖由 evaspring 于 2009-3-30 16:58 发表
没有什么真正可靠的随机数种子,这样的数字不是很随机么?

假如 产生 13个数字 1 ~13 都有了 那才不正常了呢 ~

嗯,但是我觉得,这样的序列
3,9,3,10,3,4,10,4,11,4

怎么看也不觉得随机做的多好,至少不应该让我看出上面我说的某种规律吧,呵呵。
作者: jeanlove    时间: 2009-03-30 17:46
原帖由 shan_ghost 于 2009-3-30 17:23 发表
你算一算3次取得的数字都不同的概率,就知道为什么了。

http://blog.codingnow.com/2008/04/quasi-random_sequences.html
http://blog.codingnow.com/2007/11/random.html

偶数学不精通,不过这个概率应该很高吧。

连续3张扑克牌,点数都不同的概率是不是
1*(12/13)*(11/13),这是个远远大于0.5的数字啊
同理,连续4张扑克牌,点数都不同的概率,还是0.6左右。

应该是大概率事件吧。

我尝试了一下,如果运行./a.out的时间间隔大一点,确实产生的数随机性好多了。
8,3,10,11,5,13,11,5,7,2,11,6,7,8,10
作者: jeanlove    时间: 2009-03-30 17:47
原帖由 shan_ghost 于 2009-3-30 17:25 发表
另外,想取一个随机序列的话,仅初始化一次随机数发生器,然后使用这个发生器依次取出全部数字,这样得到的东西的分布才符合预期。

随机数发生器可没保证不同种子产生的第一个数的随机分布。

你这样用时间 ...

这个解释有意思!
作者: shan_ghost    时间: 2009-03-30 17:59
你的用法是错的。

随机数常用的生成算法是“线性同余法”。
http://zhidao.baidu.com/question/540840.html
http://zh.wikipedia.org/wiki/%E7 ... 9%E6%96%B9%E7%A8%8B


以百度那个简单算法为例:
不妨取a=16807,m=2147483647,以为一常数。写个简单的程序就是:
long r;

void scand( long v)//初始化随机种子数
{
r = v;
}

long rand()//产生随机数
{
r = (r*a + c)%m;//a,c,m为常数
return r;
}


可见,怎样得到一个随机数序列?

第一步,初始化r

第二步,以r = (r*a + c)%m计算新的r,这个r就是随机数序列的第一个值

第三步,以上一步得到的r值为基础,再次以r = (r*a + c)%m计算出新的r值

反复执行第三步,得到的随机数序列就有了相对较好的分布。
(换句话说,产生随机数的过程是一个迭代过程)


而你的方法则相当于:

1、设r为当前时间
2、以r = (r*a + c)%m求出一个数字
3、重新初始化r为当前时间
4、以r = (r*a + c)%m当第二个随机数字
反复执行3、4两步。

很显然,你这个做法完全破坏了随机数的产生机制,和直接用 sin(当前时间) * 13 没什么两样。这样得到的数字有随机性才叫出鬼了

[ 本帖最后由 shan_ghost 于 2009-3-30 18:06 编辑 ]
作者: 皇家救星    时间: 2009-03-30 18:40
srand(time(NULL) * 100);

换成这样呢? 会不会好一点
作者: system888net    时间: 2009-03-30 19:47


从某种程度来说,靠纯软件产生的都是"伪"随机数!




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2