伪随机数
int rand(void)
函数通常用来当做随机函数来使用,殊不知这其实是一个伪随机函数。按照某种顺序生成的随机函数,这是什么意思呢?我们来测试一下,
第一次:
cout << "first:" << endl; cout << rand() << endl; cout << rand() << endl; cout << rand() << endl;
第二次
发现,只要程序重复运行每次生成的随机数都是一样的!!这就是伪随机数的概念。如何改进呢?
种子
我们力求每次都要随机成功,引入一个随机数种子的概念,种子和随机数的产生是有因果关系的,同一个种子,只会产生同一种随机数,随机数种子是由一个种子函数来指定的,它就是void srand(unsigned int seed)
,当没有设置的时候,系统默认是1,我们要保证每次进入系统种子都会改变,通常的习惯是用时间来定为种子,因为时间一直在流逝,time(NULL)返回一个1970-1-1 00:00:00到当前时间的秒数。可以做为种子。 srand(time(NULL))
就像这样
int _tmain(int argc,TCHAR* argv[]) { srand((unsigned)time(NULL)); cout << rand() << endl; cout << rand() << endl; cout << rand() << endl; cin.get(); return 0; }
先指定再使用。严格的说这个还是一个伪随机函数 ,但也基本达到了完全随机的效果。
获得两个区间之间的随机值,普遍想到的方法是:
要取得[a,b)的随机整数,使用(rand() % (b-a))+ a;
要取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a;
要取得(a,b]的随机整数,使用(rand() % (b-a))+ a + 1;
这个办法很好理解,但是我喜欢先得到0-1之间的随机值,再乘以b-a,最后再加上a。
double dVal = ((double)rand()/RAND_MAX) return iMin + dVal * (iMax - iMin)
确定区间的方法都是一样的,理解哪个用哪个!
思考
我们虽然写出了相对随机的随机数函数,但是细心的人会发现一个问题,就是随机数区间的概率问题,假如我们需要求1到3之间的随机数,我们期望是等概率的,但是事实却不是。
我们知道,rand()
函数获得的区间是[0,RAND_MAX),假若用求余数的方法,RAND_MAX的值是0x7fff,可得(0x7fff-1)%3=0,看上去好像每个数出现的次数一致,别忘了我们还包含一个0,也就是说0出现的次数多,不是等概率的。
具体怎么办留给大家思考,欢迎在评论区探讨