新标准之前,使用C库rand生成随机数,生成均匀分布的伪随机整数,每个随机数的范围在0和一个系统相关的最大值(至少为 32767 ) 之间。但是无法自定义是否均匀分布、随机范围、随机数类型。
新标准通过以下一组类来满足有关随机数的需求:
- 随机数引擎类
- 是一个函数对象,不接受参数,返回一个随机unsigned。
- 随机数分布类
- 使用引擎返回服从特定概率分布的随机数。
- 都是模板,除了bernoulli_distribution。
随机数发生器:引擎类 + 分布类。
#include<random> // 在头文件random中。
uniform_int_distribution<unsigned> u(0,9); // 分布类型:均匀分布,0~9的unsigned
default_random_engine e; // 引擎类型:编译器选择的默认引擎。
cout << u(e) << " "; // u(e):随机数发生器,返回一个unsigned int
随机数引擎
一个函数对象,不接受参数,返回一个随机unsigned数。
标准库有多个引擎类型,default_random_engine是一个类型别名,表示由编译器指定的默认引擎类型。
default_random_engine e; // 使用编译器默认的随机数引擎,生成随机无符号数
for(size_t i = 0; i < 10; ++i)
cout << e() << " ";
//16807 282475249 1622650073 984943658 1144108930 470211272
uniform_int_distribution<unsigned> u(0,9); // 分布类型:均匀分布,0~9的unsigned int
default_random_engine e; // 引擎类型:编译器默认。
for (size_t i= 0; i < 10; ++i)
// 将u作为随机数源,每个调用返回在指定范围内并服从均匀分布的值
cout << u(e) << " " // 0 1 7 4 5 2 0 6 6 9
支持的操作
Engine e; // 默认构造函数,使用该引擎类型默认的种子
Engine e(s); // 使用整型值s作为种子
e.seed(s); // 使用种子s重置引擎的状态
e.min(); // 此引擎可生成的最小值
e.max(); // 此引擎可生成的最大值
Engine::result_type // 此引擎生成的unsigned整型类型
e.discard(u) // 将引擎推进u步,u类型为unsigned long long
序列相同问题,一个给定的随机数发生器一直会生成相同的随机数序列。
如果定义了局部的发生器,应该将其定义为static,来保存状态,每次生成的都是新的数,避免重复生成序列。
void func(){
uniform_int_distribution<unsigned> u(0,9);
default_random_engine e;
for (size_t i= 0; i < 10; ++i)
cout << u(e) << " ";
//每次func()的结果都是:0 1 7 4 5 2 0 6 6 9
}
void func(){
// 定义为static,保存状态
static uniform_int_distribution<unsigned> u(0,9);
static default_random_engine e;
for (size_t i= 0; i < 10; ++i)
cout << u(e) << " "; //每次func()的结果都不一样。
}
种子seed
就是一个数值,引擎可以利用它从序列中一个新位置重新开始生成随机数。
种子是否相同,决定随机序列是否相同。
所以选择种子非常讲究,下面例子中有一个稍微随机一点的种子。
default_random_engine e1; // 使用默认种子
default_random_engine e2(2147483646); // 使用给定的种子值
default_random_engine e3; // 使用默认种子值
e3.seed(32767); // 调用seed设置一个新种子值
default_random_engine e4(32767); // 将种子值设置为32767
// e3和e4有相同的种子seed,将生成相同的序列。
// time在头文件ctime中
// time(data),返回当前距某个特定时刻过了多少秒,输入到data中。
// time(0),直接返回秒数
//
// 随机改变的种子值
// 但还是不够随机,函数运行在1s之内,种子就相同。
//
default_random_engine el(time(0));
随机数分布类
分布类型都是模板,接受一个模板参数,表示生成的随机数的类型。
浮点值分布类型,默认是double型随机数。
整型分布类型,默认是int型随机数。
uniform_real_distribution<> u(0, 1); // 默认生成double值
// 空<>表示我们希望使用默认结果类型
uniform_real_distribution<double> u(0,1); // 0到1(包含)的均匀分布,返回double类型
uniform_int_distribution<unsigned> u(0,9); // 返回unsigned int类型。
支持的操作
Dist d; // 默认构造函数;使d准备好被使用。
// 其他构造函数依赖于Dist的类型
// 分布类型的构造函数是explicit的
d(e) // 用相同的e连续调用d的话,会根据d的分布式类型生成一个随机数序列;
// e是一个随机数引擎对象
d.min() // 返回d(e)能生成的最小值
d.max() // 返回d(e)能生成最大值
d.reset() // 重建d的状态,使得随后对d的使用不依赖于d已经生成的值
类型
均匀分布
// IntT:表示整型类型,不包括bool、char,short、int、long
// RealT:表示浮点类型,float、double、long double
//生成指定类型的,在给定包含范围内的值。
uniform_int_distribution<IntT> u(m=0, n=max); // m最小值,n是IntT类型的最大值
uniform_real_distribution<RealT> u(x=0.0, y=1.0); // m最小值,n最大值
//空<>表示我们希望使用默认结果类型
uniform_real_distribution<> u(0, 1); // 默认生成double值
uniform_int_distribution<> u(0, 9); // 默认生成int
伯努利分布
// IntT:表示整型类型,不包括bool、char,short、int、long
// RealT:表示浮点类型,float、double、long double
bernoulli_distribution b(p=0.5); // p概率返回true
binomial_distribution<IntT> b(t=1, p=0.5); // t:采用大小,整型值。
geometric_distribution<IntT> g(p=0.5); // 每次试验成功的概率p
negative_binomial_distribution<IntT> nb(k=1, p=0.5); // k次试验成功的概率为p
default_random_engine e;
bernoulli_distribution b(.55); // 0.55的概率返回true
b(e); //0.55的概率返回true
泊松分布
// IntT:表示整型类型,不包括bool、char,short、int、long
// RealT:表示浮点类型,float、double、long double
poisson_distribution<IntT> p(x); // 均值为x的分布,x为double类型。
//指数分布,参数lambda通过浮点值lam给出
exponential_distribution<RealT> e(lam=1.0);
gamma_distribution<RealT> g(a=1.0, b=1.0); // 形状参数a, 尺度参数b
weibul.l._distribution<Real.T> w(a=1.0, b=1.0); // 形状参数为a, 尺度参数为b的分布
extreme_value_distribution<Real.T> e(a=0.0, b=1.0);
正态分布
// IntT:表示整型类型,不包括bool、char,short、int、long
// RealT:表示浮点类型,float、double、long double
normal_distribution<RealT>n(m=0.0, s=1.0); // 均值:m,标准差:S
lognormal_distribution<RealT>ln(m=0.0, s=1.0); // 均值:m,标准差:S
chi_squared_distribution<RealT>c(x=1.0); // 自由度为x
cauchy_distribution<RealT>c(a=0.0, b=1.0); // 位置参数a和尺度参数b
fisher_f_distribution<RealT>f(m=1, n=1); // 自由度为m和n
student_t_distribution<RealT>s(n=1); // 自由度为n
抽样分布
// IntT:表示整型类型,不包括bool、char,short、int、long
// RealT:表示浮点类型,float、double、long double
discrete_distribution<IntT> d(i, j); // i和j是一个权重序列的输入迭代器
discrete_distribution<IntT> d{ il }; // il是一个权重的花括号列表,必须能转成double
piecewise_constant_distribution<RealT> pc(b,e,w); // b、e和w是输入迭代器。
piecewise_linear_distribution<RealT> pl(b,e,w); // b、e和w是输入迭代器。