随机数

前言

使用c++时经常要用到随机数, 本文对c++的随机数api做个简单的总结

传统方法

c++11之前一般会用srand()配合rand()来实现随机数的使用

比如

1
2
3
4
for (int i=0; i<10;i++)
{
cout << rand() % 10 << " ";//返回0-9的随机数
}

image-20210721144150064

1
2
3
4
5
for (int i=0; i<10;i++)
{
srand(1);
cout << rand() % 10 << " ";
}

image-20210721144237834

1
2
3
4
5
for (int i=0; i<10;i++)
{
srand(i%2);
cout << rand() % 10 << " ";
}

image-20210721144316345

c++11随机数算法

c++11提供了3个新的随机算法

  • linear_congruential_engine线性同余法
  • mersenne_twister_engine梅森旋转法
  • substract_with_carry_engine滞后Fibonacci

借用网络图用一下

image-20210721144503338

如果我们要使用这三个模板类的话,就必须自己实例化之。但这些实例化参数都是这些算法里面使用到的参数,如果不懂算法的原理的话,真的不知道需要用什么参数才能得到比较好的随机序列。所以我们这些卑微的码农是用不了这些模板类的。C++11标准也想到了这点,所以就帮我们预定义了一些随机数类,这些随机数类都是用比较好的参数实例化上面那三个模板类。注意:在C++11里面,把这些随机数生成器叫做引擎(engines)。

直接开撸

1
2
3
4
5
std::default_random_engine  random;	
for (int i=0; i<10;i++)
{
cout << random() << endl;
}

结果就不显示了, 一堆随机数

同样的, 也可以设置随机种子(seed),方法是往构造函数传入参数或者使用 random.seed()来设置

1
2
std::default_random_engine  random(1);
//等价于 random.seed(1);

1
2
3
4
5
6
7
8
std::default_random_engine  random;
std::uniform_int_distribution<int> dis1(0, 100);
std::uniform_real_distribution<double> dis2(0.0, 1.0);
for (int i=0; i<10;i++)
{
cout << dis1(random) <<endl;
cout << dis2(random) << endl;
}

image-20210721144827258

用上述两个模板类来生成的均是均匀分布的随机数, 基本已经能满足一般的项目需求了

需要注意的是

uniform_int_distribution的随机数的范围是 [ ]

uniform_real_distribution却是半开范围 [ )

如果需要浮点数随机范围是[],那么按照如下使用

1
std::uniform_real_distribution<double> dis2(0, std::nextafter(1,DBL_MAX));

其他算法

C++11提供的概率分布类型有下面这些:

均匀分布:

uniform_int_distribution          整数均匀分布
uniform_real_distribution        浮点数均匀分布

伯努利类型分布:(仅有yes/no两种结果,概率一个p,一个1-p)

bernoulli_distribution    伯努利分布
binomial_distribution     二项分布
geometry_distribution    几何分布
negative_biomial_distribution  负二项分布

Rate-based distributions:

poisson_distribution 泊松分布
exponential_distribution指数分布
gamma_distribution 伽马分布
weibull_distribution 威布尔分布
extreme_value_distribution 极值分布

正态分布相关:

normal_distribution        正态分布
chi_squared_distribution卡方分布
cauchy_distribution       柯西分布
fisher_f_distribution      费歇尔F分布
student_t_distribution t分布

分段分布相关:

discrete_distribution离散分布
piecewise_constant_distribution分段常数分布
piecewise_linear_distribution分段线性分布

泊松分布

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
std::default_random_engine  random;
std::uniform_int_distribution<int> dis1(0, 100);
std::uniform_real_distribution<double> dis2(0.0, 1.0);
std::poisson_distribution<int> dis3(2.5);
int p[10] = {};
for (int i=0; i<10000;i++)
{
int n = dis3(random);
if (n < 10)
{
p[n]++;
}
}
for (int i =0; i< 10; i++)
{
cout<< i << " : "<< string(p[i]*0.01, '*') << endl;
}

image-20210721151336229

上图显示的就是如下图的情况

image-20210721151404832