我们先来看看下面几句代码:
#define RAND_MAX implementation_defined
int rand();
void srand(unsigned int i);
RAND_MAX是系统中一个很大的整数,至于为什么说很大而没有说多大是因为不同的系统中这个整数的大小不一样。
rand()产生0~RAND_MAX间的伪随机数。为什么说是伪随机数呢?因为真随机数就像永动机一样,靠程序是无法实现的。这个伪随机数的重复周期比较长罢了,所以一般情况下我们都当着真随机数在用。
srand(i)是将i作为随机数生成器的 种子。参数i必须是个正整数,如i为某个确定的整数,则每次生成的随机序列是一样的。所以我们一般采用系统时间(unsigned)time(NULL)作为随机数的种子。
随机数生成器代码如下:
#include"name_space.h"
#include<ctime>
using namespace my_std;
void foo(){
int a[10];
srand((unsigned)time(NULL));
//srand(100);
for(int i=0;i<10;++i){
a[i] = rand()%10;//生成0~9可以重复的随机数
}
for(int i=0;i<10;++i)
cout<<a[i]<<' ';
cout<<endl;
}
int main(){
foo();
}
name_space.h是我自己定义的一个头文件,目的如下,一看就懂。
#ifndef _NAME_SPACE_H
#define _NAME_SPACE_H
#include<iostream>
namespace my_std{
using std::cout;
using std::endl;
using std::rand;
using std::srand;
}
#endif
rand()产生的随机数地位常常很可疑,所以rand()%n并不是很好的产生0到n-1之间随机数的可移植方式。
然而采用int((double(rand())/RAND_MAX)*n)产生的随机数往往更能让人接受。
所以上述代码修改为:
void foo(){
int a[10];
srand((unsigned)time(NULL));
//srand(100);
for(int i=0;i<10;++i){
a[i] = int((double(rand())/RAND_MAX)*10);//生成0~9可以重复的随机数
}
for(int i=0;i<10;++i)
cout<<a[i]<<' ';
cout<<endl;
}
int main(){
foo();
}
若是使用上面的算法,有一个小问题就是这个随机数会有n的可能性,虽然这种可能性很低。所以在需求比较严格的地方,做好检查工作。
上述的随机数是均匀分布的,可以进行统计测试。
我们再来看看boost库里面的随机数生成器。
boost库中有各种各样的随机数生成器,不同的生成器性能不同,让人看得头昏眼花。库的说明文档指出,如果你没有明确的选择要求,就用mt19937。好吧,我不明确。
#include<boost\random.hpp>
using namespace boost::random;
int main(){
boost::mt19937 rgv(time(0));
for(int i=0;i<10;++i)std::cout<<rgv()%10<<" ";
std::cout<<std::endl;
}
下面我们来看看Stroustrop老大写的一个随机数生成器。
#include"name_space.h"
#include<cmath>
using namespace my_std;
class Randint{
unsigned long randx;
public:
Randint(long s=0){randx = 0;}
void seed(long s){randx = s;}
long abs(long x){
return x&0x7fffffff;
}
static double max(){
return 2147483648.0;
}
long draw(){
return randx = randx*1103515245 +12345;
}
double fdraw(){
return abs(draw())/max();
}
long operator()(){
return abs(draw());
}
};
class Urand:public Randint{
long n;
public:
Urand(long nn){n = nn;}
long operator()(){
long r = n*fdraw();
return (r==n)?n-1:r;
}
};
class Erand:public Randint{
long mean;
public:
Erand(long m){
mean = m;
}
long operator()(){
return -mean*log((max()-draw())/max()+.5);
}
};
int main(){
Urand draw(10);
map<int,int>bucket;
for(int i=0;i<100000;++i)bucket[draw()]++;
for(int i=0;i<10;++i)cout<<bucket[i]<<endl;
}
我们来看看结果分布:
每个数的出现次数都接近10000,果然是均匀分布。draw(10)生成0~9之间的数,这个生成器还不能生成小数,意思就是如果你想得到[0,1)之间的随机数,需要做稍微的改动。
现在,有木有发现随机数是很有意思的一个东西?