目录
C++11之前随机数都是使用C函数库rand来生成,此函数生成均匀分布的伪随机数(0~32767);C++11中对随机数生成进行增强。
随机数简介
C++11在<random>中定义了一组类用于实现随机数:
-
随机数引擎类:生成随机数
-
随机数分布类:生成满足指定分布的随机数
随机数引擎
标准库提供了一个非确定性随机数生成设备random_device
,能产生min()~max()
间的一个数字(一般只用作种子,调用代价相对较高:因其产生随机数时会依赖于熵池中的噪声资源,必须等待收集到足够多的噪声才能产生新的种子):
-
Linux的实现是读取/dev/urandom设备;
-
Windows的实现是用rand_s,使用操作系统来生成加密安全的伪随机数;
C++11中常用来做伪随机数算法的有以下几种:
-
linear_congruential_engine线性同余法:速度最快、也常用;
-
mersenne_twister_engine梅森旋转法:生成的随机数质量比较高;
-
substract_with_carry_engine滞后Fibonacci法;
此外default_random_engine是一个实例化的类。它的实现是由编译器厂家决定的,可能用linear_congruential_engine也可能用mersenne_twister_engine实现。常用操作方法:
-
seed(s):使用种子s重置引擎;
-
min()/max():引擎生成的最大、最小值;
-
discard(n):将引擎推进n步(即丢弃n个随机数);
-
operator():获取下一个随机数;
random_device rd;
default_random_engine rg{rd()}; // 若不用rd()初始化,则每次生成的随机数都是一样的
for(size_t i=0; i<10; i++)
cout << rg() << ", ";
随机分布
通过随机分布模板,可以生成满足指定分布特性的随机数。
-
均匀分布:uniform_int_distribution(整数,返回
[low,upper]
)和uniform_real_distribution(浮点数,返回[low,upper)
); -
伯努利类型分布:bernoulli_distribution(伯努利分布)、binomial_distribution(二项分布)、 geometry_distribution(几何分布)、negative_biomial_distribution(负二项分布);
-
Rate-based分布: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(分段线性分布);
通过随机分布与随机引擎组合,即可方便产生符合指定分布的随机数。
随机数应用
编写一个简单随机数生成类,可以生成单个或一组随机数:
class XRand{
protected:
random_device m_rd;
default_random_engine m_re{m_rd()};
// mt19937 m_re{m_rd()};
public:
int operator()(){
return Next();
}
virtual int Next(){
return m_re();
}
vector<int> Next(int nCount){
vector<int> vec;
std::generate_n(back_inserter(vec), nCount, [this](){return Next();});
return vec;
}
}
生成满足均匀分布的随机数:
class XUniformRand:public XRand{
uniform_int_distribution<> m_uni;
public:
explicit XUniformRand(int nMax, int nMin=0)
: m_uni{nMin, nMax} {}
using XRand::Next;
virtual int Next() override {
return m_uni(m_re);
}
}
生成满足正态分布的随机数:
class XNormalRand:public XRand{
normal_distribution<> m_nor; // 生成的都是浮点数
public:
explicit XNormalRand(int nMean, int nstddev=1)
: m_nor{nMean, nstddev} {}
using XRand::Next;
virtual int Next() override {
return (int)m_nor(m_re);
}
}