随机数的简单生成
关于随机数的问题,总的来说,我们用srand()和rand()产生的是伪随机数。也就是说,根据一个seed,在一个范围内,由算法公式产生的一个数列,每一个数与它的上一个数有关。如果seed相同,那么产生的随机数列也就相同,而srand()就是用于获得这样的一个seed。
所以,我们可以用#include<ctime>的(unsigned)time( NULL )来获得时间作为种子。头文件要加上
#include<iostream>
#include<ctime>
#include<cstdlib>
usingnamespacestd;
而且,需要注意的是,
程序段1:
void main() {
int count=0;
for (int i=0;i<10;i++){
srand((unsigned)time(NULL));
count++;
。。。
与程序段2:
void main() {
int count=0;
srand((unsigned)time(NULL));
for (int i=0;i<10;i++){
count++;
。。。
是不同的,是由于srand()在循环内外的不同,srand()函数放在循环体内,而程序执行的CPU时间较快,调用time函数获取的时间精度却较低(55ms),这样循环体内每次产生随机数用到的种子数都是一样的,因此产生的随机数也是一样的。
同时,我们还有一个#include<windows.h>里的GetTickCount()用于返回(retrieve)从操作系统启动到现在所经过(elapsed)的毫秒数,返回值是DWORD。所以srand(GetTickCount());语句也可以。
C++中不能使用random()函数
random函数不是ANSI C标准,不能在gcc,vc等编译器下编译通过。可改用C++下的rand函数来实现。
1、C++标准函数库提供一随机数生成器rand,返回0-RAND_MAX之间均匀分布的伪随机整数。 RAND_MAX必须至少为32767。rand()函数不接受参数,默认以1为种子(即起始值)。随机数生成器总是以相同的种子开始,所以形成的伪随机数列也相同,失去了随机意义。(但这样便于程序调试)
2、C++中另一函数srand(),可以指定不同的数(无符号整数变元)为种子。但是如果种子相同,伪随机数列也相同。一个办法是让用户输入种子,但是仍然不理想。
3、比较理想的是用变化的数,比如时间来作为随机数生成器的种子。 time的值每时每刻都不同。所以种子不同,所以,产生的随机数也不同。
// C++随机函数(VC program)
#include <stdio.h>
#include <iostream>
#include <time.h>
using namespace std;
#define MAX 100
int main(int argc, char* argv[])
{
srand((unsigned)time(NULL ) );//srand()函数产生一个以当前时间开始的随机种子.应该放在for等循环语句前面 不然要很长时间等待
for (int i=0;i<10;i++)
cout<<rand()%MAX<<endl;//MAX为最大值,其随机域为0~MAX-1
return 0;
}
rand()的用法
rand()不需要参数,它会返回一个从0到最大随机数的任意整数,最大随机数的大小通常是固定的一个大整数。这样,如果你要产生0~10的10个整数,可以表达为:
int N = rand() % 11;
这样,N的值就是一个0~10的随机数,如果要产生1~10,则是这样:
int N = 1 + rand() % 11;
总结来说,可以表示为:
a + rand() % n
其中的a是起始值,n是整数的范围。
a + rand() %(b-a+1) 就表示 a~b之间的一个随机数
若要0~1的小数,则可以先取得0~10的整数,然后均除以10即可得到随机到十分位的10个随机小数,若要得到随机到百分位的随机小数,则需要先得到0~100的10个整数,然后均除以100,其它情况依
此类推。
通常rand()产生的随机数在每次运行的时候都是与上一次相同的,这是有意这样设计的,是为了便于程序的调试。若要产生每次不同的随机数,可以使用srand( seed )函数进行随机化,随着seed的不同,就能够产生不同的随机数。
如大家所说,还可以包含time.h头文件,然后使用srand(time(0))来使用当前时间使随机数发生器随机化,这样就可以保证每两次运行时可以得到不同的随机数序列(只要两次运行的间隔超过1秒)。
关于伪随机数的生成
用计算器或计算机产生的随机数,它的优点在于统计方便、速度快,缺点在于,计算器或计算机产生的随机数是根据确定的算法产生的,具有周期性(周期很长),具有类似随机数的性质,但并不是真正的随机数,是伪随机数。
而为随机数的应用只能解决一般的小问题,而对于一些特殊的问题,必须采用更好的算法,不能用提供的随机算法rand()来解决,对于这样一组产生的随机数曾有前辈做过研究,证明他的可取性不大,在一些问题上可能会有影响,给客户带来麻烦。
(参考:http://blog.codingnow.com/2007/11/random.html)
本文主要说的是伪随机数的生成问题,而不是针对更多的数学定义上的随机数生成,据本人简单查询,随机数生成还有其他数学方法,而这些算法,都在追求所得的数尽量随机。
而一般我们所采用的随即算法,在软件计算机常用的产生随机数的算法为线性同余算法,即下面的公式递推产生不同的随机数。
ni=(a*ni+b)modM 其中i=0,1,…M-1
或者一般的古典算法:
V = ( ( V * 2 ) + B .xor. B ... )(Mod2^n)
N+1 N 0 2
V是要取的随机数, B是个种子, n是随机数的最大个数
(对于详细的随机算法可参考:
http://blog.youkuaiyun.com/lchunli/article/details/4782821)
注:1)通常情况下,随机种子的选取还有很多种,其他办法,比如:用物理上更随机的量做种子,系统时间、两次敲击键盘的时间间隔、多次移动鼠标的偏移、甚至系统出错的出错信息码等等,其核心是让所得的“随机数”更趋近于随机。
2)引用到的网站:
http://blog.codingnow.com/2007/11/random.html
http://blog.sina.com.cn/s/blog_59b830f60100cgd3.html
http://www.pep.com.cn/gzsx/jszx_1/czsxtbjxzy/xkbsyjc/jxsj/bx3/201008/t20100826_757297.htm
http://www.cnblogs.com/dengshunping/archive/2009/06/18/1505799.html
http://iask.sina.com.cn/b/1550912.html
http://blog.youkuaiyun.com/lchunli/article/details/4782821
补充后记
近期做C++开发,要用到随机数,且是微秒甚至纳秒情况下需要使用多次,这造成了随机出产生的初始种子相同的情况,这使得获取到的随机数存在很多相同的风险。
基于如上高频次使用随机数存在多个相同随机数的问题,我调整后的解决方案为空间换时间。
提前生成一个65535(或者更多)个随机数的列表,相同毫秒下的随机数第一次随机生成0-65534的起始编号,然后依次遍历使用,当种子数发生变化时,再重新生成起始编号。这样就能解决如上所出的问题