Published on

随机数

前言

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

传统方法

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

比如

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

image-20210721144150064

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

image-20210721144237834

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)。

直接开撸

std::default_random_engine  random;
for (int i=0; i<10;i++)
{
    cout << random() << endl;
}

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

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

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

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却是半开范围 [ )

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

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分段线性分布

泊松分布

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