随机数引擎
linear_congruential_engine 实现线性同余算法
mersenne_twister_engine 实现梅森缠绕器算法
subtract_with_carry_engine 实现带进位减(一种延迟斐波那契)算法
以上三个引擎都是类模板,它们第一个模板参数都是UIntType,表示生成数字的类型,且在内部被定义为result_type成员类型,其他模板参数是特定算法需要的参数。
它们的构造函数类似,以linear_congruential_engine为例说明:
linear_congruential_engine() : linear_congruential_engine(default_seed) {} (1)
explicit linear_congruential_engine(result_type value); (2)
template <class Sseq>
explicit linear_congruential_engine(Sseq& s); (3)
linear_congruential_engine(const linear_congruential_engine&); (4)(隐式声明)
构造引擎并初始化状态。
(1)默认构造函数。以 default_seed 播种引擎。
仅若 Sseq 符合种子序列要求,(3)才参与重载决议。尤其是若 Sseq 可转换为 result_type,则从候选函数集中排除该重载。
类 std::seed_seq 满足种子序列的要求。一个 seed_seq 对象消耗整数值数列,并基于消耗的数据生成请求数量的无符号整数值 i,0<=i < 2^32。产生的值分布在整个 32 位范围上,即使消耗的值接近。seed_seq 的构造函数和 generate 函数声明如下:
seed_seq();
seed_seq(const seed_seq&) = delete;
template <class InputIt>
seed_seq(InputIt begin, InputIt end);
template <class T>
seed_seq(std::initializer_list<T> il);
template <class RandomIt>
void generate(RandomIt begin, RandomIt end);
一个简单的例子:
#include <random>
#include <cstdint>
#include <iostream>
int main()
{
std::seed_seq seq{1,2,3,4,5};
std::vector<std::uint32_t> seeds(10);
seq.generate(seeds.begin(), seeds.end());
for (std::uint32_t n : seeds) {
std::cout << n << '\n';
}
return 0;
}
回到三个随机数引擎上,它们还有一些公共的成员函数:
void seed(result_type value = default_seed);
template <class Sseq>
void seed(Sseq& seq);
用新种子值重新初始化随机数引擎的内部状态。
result_type operator()();
生成伪随机数。令引擎状态前进一个位置。
void discard(unsigned long long z);
令内部状态前进 z 次。等价于调用 operator() z 次并舍弃结果。
static constexpr result_type min();
返回随机数引擎潜在生成的最小值。此值等于 0u 。
static constexpr result_type max();
返回随机数引擎潜在生成的最大值。
此外还有以下非成员函数:
operator==
operator!=
比较两个伪随机数引擎的内部状态
operator<<
operator>>
执行伪随机数引擎的流输入和输出
前者序列化引擎的内部状态为一或多个空格分隔的十进制数序列,并插入到流。后者能将十进制数序列还原为原引擎。
随机数引擎适配器
template <class Engine, size_t P, size_t R>
class discard_block_engine;
discard_block_engine 忽略基础引擎所产生的一定量数据。
生成器只从基础引擎生成的每个 P 大小的块保留 R 个数,舍弃剩余的数。
P - 块大小。必须大于 0 。
R - 每块用的数字数。必须大于 0 且不大于 P 。
template <class Engine, std::size_t W, class UIntType>
class independent_bits_engine;
class independent_bits_engine 将一个随机数引擎的输出适配为具有特定比特数的数字。
W - 生成数字应有的比特数,其他位填0。必须大于零,且不大于 std::numeric_limits<UIntType>::digits。
UIntType - 生成的随机数类型。类型必须是无符号整数类型。
std::independent_bits_engine<default_random_engine, 4, unsigned> e;
std::cout << '[' << e.min() << ", " << e.max() << ']' << std::endl; //输出结果是[0, 15]
template <class Engine, std::size_t K>
class shuffle_order_engine;
shuffle_order_engine 打乱基础引擎生成的随机数。
它维护一个大小为 K 的表,并在请求时随机地从该表派送被选择数,将它替换为基础引擎生成的数。
非确定随机数
std::random_device 是生成非确定随机数的均匀分布整数随机数生成器。
std::random_device 可以以实现定义的伪随机数引擎实现,在某些实现中可能每个 std::random_device 对象生成同一数值序列。
std::random_device 一般作为其他随机数引擎的种子使用。
random_device() : random_device(/*implementation-defined*/) {}
explicit random_device(const std::string& token);
标准期待 token 指定产生随机数字的字节设备,比如 linux 下的 /dev/random 。
random_device(const random_device& ) = delete;
random_device& operator=(const random_device&) = delete;
result_type operator()();
生成均匀分布的非确定随机值。
static constexpr result_type min();
返回随机数引擎潜在生成的最小值。此值等于 0u 。
static constexpr result_type max();
返回随机数引擎潜在生成的最大值。此值等于 std::numeric_limits<unsigned int>::max() 。
简单例子:
#include <iostream>
#include <random>
int main()
{
std::uniform_int_distribution<int> d(0, 10);
std::random_device rd1; // 使用 RDRND 或 /dev/urandom
for(int n = 0; n < 10; ++n)
std::cout << d(rd1) << ' ';
std::cout << '\n';
std::random_device rd2("/dev/random"); // Linux 上更慢
for(int n = 0; n < 10; ++n)
std::cout << d(rd2) << ' ';
std::cout << '\n';
}
预定义生成器
minstd_rand0
std::linear_congruential_engine<std::uint_fast32_t, 16807, 0, 2147483647>
由 Lewis、Goodman 及 Miller 发现于 1969,由 Park 与 Miller 于 1988 采纳为“最小标准”
minstd_rand
std::linear_congruential_engine<std::uint_fast32_t, 48271, 0, 2147483647>
较新的“最小标准”,为 Park、 Miller 及 Stockmeyer 于 1993 推荐
mt19937
std::mersenne_twister_engine<std::uint_fast32_t, ...
32 位梅森缠绕器,由松本与西村发现于 1998
mt19937_64
std::mersenne_twister_engine<std::uint_fast64_t, ...
64 位梅森缠绕器,由松本与西村设计于 2000
ranlux24_base std::subtract_with_carry_engine<std::uint_fast32_t, 24, 10, 24>
ranlux48_base std::subtract_with_carry_engine<std::uint_fast64_t, 48, 5, 12>
ranlux24
std::discard_block_engine<std::ranlux24_base, 223, 23>
24 位 RANLUX 生成器,由 Martin Lüscher 与 Fred James 设计于 1994
ranlux48
std::discard_block_engine<std::ranlux48_base, 389, 11>
48 位 RANLUX 生成器,由 Martin Lüscher 与 Fred James 设计于 1994
knuth_b
std::shuffle_order_engine<std::minstd_rand0, 256>
default_random_engine
实现定义
一般来说像下面这样用:
#include <random>
#include <iostream>
int main()
{
std::random_device rd;
std::default_random_engine gen(rd());
for(int i=0; i<10; ++i)
std::cout << gen() << ' ';
return 0;
}
用于产生满足特定分布数字的类/类模板/函数模板
generate_canonical
template <class RealType, size_t bits, class Generator>
RealType generate_canonical(Generator& g);
生成范围 [0, 1) 中的随机浮点值。
RealType - 浮点类型。
bits - 精度,如果该值大于RealType的精度,将使用 numeric_limits<RealType>::digits 。
简单例子:
#include <random>
#include <iostream>
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
for(int n = 0; n < 10; ++n) {
std::cout << std::generate_canonical<double, 10>(gen) << ' ';
}
}
均匀分布
uniform_int_distribution
产生在一个范围上均匀分布的整数值。(类模板)
uniform_real_distribution
产生在一个范围上均匀分布的实数值。(类模板)
伯努利分布
bernoulli_distribution
产生伯努利分布上的 bool 值。(类)
binomial_distribution
产生二项分布上的整数值。(类模板)
negative_binomial_distribution
产生负二项分布上的整数值。(类模板)
geometric_distribution
产生几何分布上的整数值。(类模板)
泊松分布
poisson_distribution
产生泊松分布上的整数值。(类模板)
exponential_distribution
产生指数分布上的实数值。(类模板)
gamma_distribution
产生 Γ 分布上的实数值(类模板)
weibull_distribution
产生威布尔分布上的实数值。(类模板)
extreme_value_distribution
产生极值分布上的实数值。(类模板)
正态分布
normal_distribution
产生标准正态(高斯)分布上的实数值。(类模板)
lognormal_distribution
产生对数正态分布上的实数值。(类模板)
chi_squared_distribution
产生 χ2 分布上上的实数值。(类模板)
cauchy_distribution
产生柯西分布上的实数值。(类模板)
fisher_f_distribution
产生费舍尔 F 分布上的实数值。(类模板)
student_t_distribution
产生学生 t 分布上的实数值。(类模板)
采样分布
discrete_distribution
产生离散分布上的随机整数。(类模板)
piecewise_constant_distribution
产生分布在常子区间上的实数值。(类模板)
piecewise_linear_distribution
产生分布在定义的子区间上的实数值。(类模板)
以上的类或类模板使用方式都是类似的,构造函数根据参数生成概率分布函数,使用operator()()根据关联的概率分布函数生成随机数。
他们主要有以下常用成员:
成员类型result_type,operator()()的返回值。
void reset();
重置分布对象的内部状态
template <class Generator>
result_type operator()(Generator& g);
根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。
result_type min() const;
返回分布潜在生成的最小值。
result_type max() const;
返回分布潜在生成的最大值。
看一个正态分布的例子:
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <cmath>
int main()
{
std::random_device rd{};
std::mt19937 gen{rd()};
// 值最可能接近平均
// 标准差影响生成的值距离平均数的分散
std::normal_distribution<> d{5,2};
std::map<int, int> hist;
for(int n=0; n<50000; ++n)
{
++hist[std::round(d(gen))];
}
for(auto &p : hist)
{
std::cout << std::setw(2)
<< p.first << ' ' << std::string(p.second/200, '*') << '\n';
}
return 0;
}
输出是:
-4
-3
-2
-1
0 **
1 *******
2 ***************
3 ******************************
4 *******************************************
5 *************************************************
6 *******************************************
7 ******************************
8 ****************
9 ******
10 **
11
12
13
14
参考 cppreference.com cplusplus.com