伪随机数生成
随机数库提供了生成随机数和伪随机数的类。这些类包括
- 均匀随机位生成器 (URBG),包括随机数引擎(伪随机数生成器,生成具有均匀分布的整数序列)和真随机数生成器(如果可用)。
- 随机数分布(例如 均匀分布、正态分布 或 泊松分布),它们将 URBG 的输出转换为各种统计分布。
URBG 和分布被设计为一起使用以产生随机值。所有随机数引擎都可以被专门地播种、序列化和反序列化,以便用于可重复的模拟器。
目录 |
[编辑] 均匀随机位生成器
均匀随机位生成器 是一个函数对象,返回无符号整数值,使得可能结果范围内的每个值都具有(理想情况下)相等的返回概率。
所有均匀随机位生成器都满足 UniformRandomBitGenerator 要求。C++20 还定义了一个 uniform_random_bit_generator
概念。
定义于头文件
<random> | |
(C++20) |
指定类型符合均匀随机位生成器的条件 (概念) |
[编辑] 随机数引擎
随机数引擎 (通常缩写为 engine) 是一个均匀随机位生成器,它使用种子数据作为熵源生成伪随机数。
在任何给定时间,类型为 E
的引擎 e 都有一个状态 ei
,对于某个非负整数 i。构造时,e 具有初始状态 e0
,这由引擎参数和初始种子(或种子序列)确定。
以下属性始终为任何引擎类型 E
定义
E
的状态大小,以E::result_type
大小的倍数表示(即 (sizeof ei
) / sizeof(E::result_type))。- 转换算法 TA,通过该算法,e 的状态 e
i
被推进到其后继状态 ei+1
(即 TA(ei
) == ei+1
)。 - 生成算法 GA,通过该算法,e 的状态被映射到类型
E::result_type
的值,结果是一个伪随机数。
可以通过交替调用 TA 和 GA 来生成伪随机数序列。
标准库提供了三种不同类型的伪随机数生成算法的实现作为类模板,以便可以自定义算法。选择使用哪个引擎涉及许多权衡
- 线性同余引擎 速度适中,并且状态的存储需求非常小。
- 梅森旋转引擎 速度较慢,状态存储需求较高,但使用正确的参数,具有最长的不重复序列和最理想的频谱特性(对于给定的理想定义)。
- 带进位减法引擎 即使在没有高级算术指令集的处理器上也非常快,但代价是更大的状态存储和有时不太理想的频谱特性。
|
(自 C++26 起) |
这些随机数引擎都不是 密码学安全的。与任何安全操作一样,应为此目的使用密码库(例如 OpenSSL RAND_bytes
)。
从这些模板实例化的所有类型都满足 RandomNumberEngine 要求。
定义于头文件
<random> | |
(C++11) |
实现 线性同余 算法 (类模板) |
(C++11) |
实现 梅森旋转 算法 (类模板) |
(C++11) |
实现带进位减法(滞后斐波那契)算法 (类模板) |
(C++26) |
一个基于计数器的可并行化生成器 (类模板) |
[编辑] 随机数引擎适配器
随机数引擎适配器使用另一个随机数引擎作为熵源来生成伪随机数。它们通常用于改变底层引擎的频谱特性。
定义于头文件
<random> | |
(C++11) |
丢弃随机数引擎的一些输出 (类模板) |
(C++11) |
将随机数引擎的输出打包成指定位数的块 (类模板) |
(C++11) |
以不同的顺序传递随机数引擎的输出 (类模板) |
[编辑] 预定义的随机数生成器
预定义了几种特定的流行算法。
定义于头文件
<random> | |
类型 | 定义 |
minstd_rand0 (C++11) |
std::linear_congruential_engine<std::uint_fast32_t, 16807, 0, 2147483647>由 Lewis、Goodman 和 Miller 于 1969 年发现,并于 1988 年被 Park 和 Miller 采纳为“最小标准” |
minstd_rand (C++11) |
std::linear_congruential_engine<std::uint_fast32_t, |
mt19937 (C++11) |
std::mersenne_twister_engine<std::uint_fast32_t, |
mt19937_64 (C++11) |
std::mersenne_twister_engine<std::uint_fast64_t, |
ranlux24_base (C++11) |
std::subtract_with_carry_engine<std::uint_fast32_t, 24, 10, 24> |
ranlux48_base (C++11) |
std::subtract_with_carry_engine<std::uint_fast64_t, 48, 5, 12> |
ranlux24 (C++11) |
std::discard_block_engine<std::ranlux24_base, 223, 23> 24 位 RANLUX 生成器,由 Martin Lüscher 和 Fred James 于 1994 年提出 |
ranlux48 (C++11) |
std::discard_block_engine<std::ranlux48_base, 389, 11> 48 位 RANLUX 生成器,由 Martin Lüscher 和 Fred James 于 1994 年提出 |
knuth_b (C++11) |
std::shuffle_order_engine<std::minstd_rand0, 256> |
philox4x32 (C++26) |
std::philox_engine<std::uint_fast32_t, 32, 4, 10, 0xCD9E8D57, 0x9E3779B9, 0xD2511F53, 0xBB67AE85> |
philox4x64 (C++26) |
std::philox_engine<std::uint_fast64_t, 64, 4, 10, 0xCA5A826395121157, 0x9E3779B97F4A7C15, 0xD2E7470EE14C6C93, 0xBB67AE8584CAA73B> |
default_random_engine (C++11) |
一个实现定义的 RandomNumberEngine 类型 |
[编辑] 非确定性随机数
std::random_device 是一个非确定性均匀随机位生成器,尽管允许实现使用伪随机数引擎来实现 std::random_device,如果不支持非确定性随机数生成。
(C++11) |
使用硬件熵源的非确定性随机数生成器 (类) |
[编辑] 随机数分布
随机数分布以后处理 URBG 的输出的方式,使得结果输出根据定义的统计概率密度函数分布。
随机数分布满足 RandomNumberDistribution。
定义于头文件
<random> | |
均匀分布 | |
(C++11) |
产生均匀分布在一定范围内的整数值 (类模板) |
(C++11) |
产生均匀分布在一定范围内的实数值 (类模板) |
伯努利分布 | |
(C++11) |
在 伯努利分布 上产生 bool 值 (类) |
(C++11) |
在 二项分布 上产生整数值 (类模板) |
在 负二项分布 上产生整数值 (类模板) | |
(C++11) |
在 几何分布 上产生整数值 (类模板) |
泊松分布 | |
(C++11) |
在 泊松分布 上产生整数值 (类模板) |
(C++11) |
在 指数分布 上产生实数值 (类模板) |
(C++11) |
在 伽玛分布 上产生实数值 (类模板) |
(C++11) |
在 韦布尔分布 上产生实数值 (类模板) |
(C++11) |
在 极值分布 上产生实数值 (类模板) |
正态分布 | |
(C++11) |
在 标准正态(高斯)分布 上产生实数值 (类模板) |
(C++11) |
在 对数正态分布 上产生实数值 (类模板) |
(C++11) |
产生符合卡方分布的实数值 (类模板) |
(C++11) |
产生符合柯西分布的实数值 (类模板) |
(C++11) |
产生符合费舍尔 F 分布的实数值 (类模板) |
(C++11) |
产生符合学生 t 分布的实数值 (类模板) |
抽样分布 | |
(C++11) |
产生符合离散分布的整数值 (类模板) |
产生分布在常数子区间上的实数值 (类模板) | |
产生分布在已定义子区间上的实数值 (类模板) |
[编辑] 实用工具
定义于头文件
<random> | |
(C++11) |
在给定精度下均匀分布实数值于[ 0, 1) (函数模板) |
(C++11) |
通用消除偏差的扰乱种子序列生成器 (类) |
[编辑] 随机数算法
定义于头文件
<random> | |
(C++26) |
使用来自均匀随机位生成器的随机数填充一个范围 (算法函数对象) |
[编辑] C 随机数库
除了上面描述的引擎和分布之外,C 随机数库中的函数和常量也可用,但不推荐使用
定义于头文件
<cstdlib> | |
生成一个伪随机数 (函数) | |
为伪随机数生成器设置种子 (函数) | |
由std::rand生成的最大可能值 (宏常量) |
[编辑] 示例
#include <cmath> #include <iomanip> #include <iostream> #include <map> #include <random> #include <string> int main() { // Seed with a real random value, if available std::random_device r; // Choose a random mean between 1 and 6 std::default_random_engine e1(r()); std::uniform_int_distribution<int> uniform_dist(1, 6); int mean = uniform_dist(e1); std::cout << "Randomly-chosen mean: " << mean << '\n'; // Generate a normal distribution around that mean std::seed_seq seed2{r(), r(), r(), r(), r(), r(), r(), r()}; std::mt19937 e2(seed2); std::normal_distribution<> normal_dist(mean, 2); std::map<int, int> hist; for (int n = 0; n != 10000; ++n) ++hist[std::round(normal_dist(e2))]; std::cout << "Normal distribution around " << mean << ":\n" << std::fixed << std::setprecision(1); for (auto [x, y] : hist) std::cout << std::setw(2) << x << ' ' << std::string(y / 200, '*') << '\n'; }
可能的输出
Randomly-chosen mean: 4 Normal distribution around 4: -4 -3 -2 -1 0 * 1 *** 2 ****** 3 ******** 4 ********* 5 ******** 6 ****** 7 *** 8 * 9 10 11 12
[编辑] 参见
C 文档 关于 伪随机数生成
|