一、前言
在很多算法中需要用到随机数,如模拟退火算法,粒子群算法,遗传算法,蚁群算法等,这些算法对随机数的质量要求较高,必须是均匀分布或者高斯分布随机数,下面介绍几种方式,不深入,但是实用。
环境:windows10,Dev-C++6.5
二、实现方法
此文所用头文件如下
#include <iostream>
#include <random>
#include <ctime>
#include <cstdio>
#include <iomanip>
using namespace std;
方式一、rand
rand函数采用线性同余法产生0-RAND_MAX之间任意随机数,不同的系统可能RAND_MAX大小不同,先看下本系统及编译器RAND_MAX的大小。
int main(void)
{
cout << RAND_MAX << endl;
return 0;
}
结果:32767
①、产生整数随机数0-10
int main(void)
{
for(int i= 1;i < 21;i++){
cout << setw(8) << rand() % 10;
if(i%5 == 0)
cout << endl;
}
return 0;
}
结果:
1 7 4 0 9
4 8 8 2 4
5 5 1 7 1
1 5 2 7 6
②、产生小数随机数0 - 1,小数点后3位有效
int main(void)
{
for(int i= 1;i < 21;i++){
cout << setw(15) << (rand() % 1000 / 1000.0);
if(i%5 == 0)
cout << endl;
}
return 0;
}
结果:
0.041 0.467 0.334 0.5 0.169
0.724 0.478 0.358 0.962 0.464
0.705 0.145 0.281 0.827 0.961
0.491 0.995 0.942 0.827 0.436
在①、②中,每次运行,得到的随机数都是相同的,这时需要添加随机种子,这样每次的结果都会不同了。
int main(void)
{
srand(time(NULL));
for(int i= 1;i < 21;i++){
cout << setw(15) << (rand() % 1000 / 1000.0);
if(i%5 == 0)
cout << endl;
}
return 0;
}
方式一在多线程运行的时候会出现随机数相同的情况,同时由于不同环境RAND_MAX不同,会给软件带来风险,而且随机数的精度不够高,比如RAND_MAX=32767,则最多小数点后5位。
方式二、mt19937
mt19937中19937是指最多可以2^19937个数不重复,这个远远大于RAND_MAX,足够我们使用。
同样,未了保证每次运行,生产的随机数不同,这里使用
random_device rnd; //操作系统,CPU硬件取的随机种子
这个随机种子基本是真正的随机数,来源于系统硬件,可以保证多线程运行任务时产生的随机数不同。在本系统中,random_device可输出最大、最小值如下,可以到,是个很大的值。
int main(void)
{
//mt19937
random_device rnd;
cout << " max:" << rnd.max() << " min:" << rnd.min() << endl;
return 0;
}
结果: max:4294967295 min:0
下面演示产生0-100均匀分布随机数,整数。每次运行,结果不同。
int main(void)
{
random_device rnd; //操作系统,CPU硬件取的随机种子
mt19937 rng(rnd());//rng(time(NULL))随机种子只能精确到S,速度快会有问题
uniform_int_distribution<int> uni(0,100);//均匀分布
for(int i= 1;i < 21;i++){
cout << setw(15) << uni(rng);
if(i%5 == 0)
cout << endl;
}
}
结果:
28 56 38 44 87
60 60 4 81 43
76 55 82 88 57
77 77 11 95 67
下面演示产生0-1均匀分布随机数,小数。每次运行,结果不同。
int main(void)
{
random_device rnd; //操作系统,CPU硬件取的随机种子
mt19937 rng(rnd());//rng(time(NULL))随机种子只能精确到S,速度快会有问题
uniform_real_distribution<double> unf(0,1);//均匀分布
for(int i= 1;i < 21;i++){
cout << setw(15) << unf(rng);
if(i%5 == 0)
cout << endl;
}
}
结果
0.575425 0.42965 0.355835 0.40992 0.299113
0.930875 0.228144 0.146019 0.797079 0.337539
0.079242 0.00467716 0.0838207 0.968054 0.449575
0.262218 0.633872 0.165048 0.0746444 0.237763
下面演示产生0-1高斯分布随机数,小数。每次运行,结果不同。
int main(void)
{
random_device rnd; //操作系统,CPU硬件取的随机种子
mt19937 rng(rnd());//rng(time(NULL))随机种子只能精确到S,速度快会有问题
normal_distribution<double> gaosi(0,1);//高斯分布
for(int i= 1;i < 21;i++){
cout << setw(15) << gaosi(rng);
if(i%5 == 0)
cout << endl;
}
}
结果
0.0837849 0.342529 0.357691 0.719499 0.717263
-0.553213 0.657816 0.0511081 -1.07223 -1.53896
-1.94554 0.96073 0.690613 -2.00728 0.708173
0.658764 -0.78627 -0.8083 0.773783 2.01785