Namespaces
Variants

Pseudo-random number generation

From cppreference.net

随机数库提供了生成随机数和伪随机数的类。这些类包括:

  • 均匀随机位生成器(URBG),包括随机数引擎(即生成均匀分布整数序列的伪随机数生成器)以及真随机数生成器(若可用)。
  • 随机数分布(例如 均匀分布 正态分布 泊松分布 ),可将URBG的输出转换为各种统计分布。

URBG和分布类被设计为协同工作以生成随机值。所有随机数引擎都可以被专门设定种子、序列化和反序列化,以便用于可重复的模拟器。

目录

均匀随机比特生成器

一个 均匀随机位生成器 是一个返回无符号整数值的函数对象,使得在可能结果范围内的每个值(理想情况下)具有相等的返回概率。

所有均匀随机比特生成器均满足 UniformRandomBitGenerator 要求。 C++20 还定义了一个 uniform_random_bit_generator 概念。

定义于头文件 <random>
指定类型符合均匀随机位生成器的要求
(概念)

随机数引擎

一个 随机数引擎 (通常简称为 引擎 )是一种均匀随机比特生成器,它使用种子数据作为熵源来生成伪随机数。

在任何给定时刻,类型为 E 的引擎 e 都拥有一个状态 e i ,其中 i 为非负整数。在构造时, e 具有初始状态 e 0 ,该状态由引擎参数和初始种子(或种子序列)决定。

以下属性始终为任何引擎类型 E 定义:

  • E 状态的大小,以 E::result_type 大小的倍数表示(即 ( sizeof e i ) / sizeof ( E :: result_type ) )。
  • 状态转移算法 TA ,通过该算法将 e 的状态 e i 推进到其后继状态 e i+1 (即 TA ( e i ) == e i+1 )。
  • 生成算法 GA ,通过该算法将 e 的状态映射为 E::result_type 类型的值,该结果即为伪随机数。

伪随机数序列可以通过交替调用 TA GA 来生成。

标准库以类模板形式提供了三种不同类别的伪随机数生成算法实现,使得算法可被定制化。选择何种引擎需权衡多方面因素:

  • 线性同余引擎 速度中等,且状态存储需求极小。
  • 梅森旋转引擎 速度较慢且状态存储需求较大,但在参数配置适当时具有最长的非重复序列和最优的光谱特性(基于对“最优”的特定定义)。
  • 带进位减法引擎 即使在无高级算术指令集的处理器上仍能保持极快速度,但代价是更大的状态存储需求以及有时相对较差的光谱特性。
  • Philox 引擎 是一种 基于计数器的随机数生成器 。它具有较小的状态量和较长的周期(不小于 2^130),适用于需要大规模并行随机数生成的蒙特卡洛模拟。该引擎易于向量化和并行化,并在 GPU 优化库中实现。
(C++26 起)

这些随机数生成器均不具备 密码学安全性 。与任何安全操作一样,此类用途应当使用密码学库(例如 OpenSSL RAND_bytes )。

所有从这些模板实例化的类型都满足 RandomNumberEngine 要求。

定义于头文件 <random>
实现 线性同余 算法
(类模板)
实现 梅森旋转 算法
(类模板)
实现带进位减法( 延迟斐波那契 )算法
(类模板)
基于计数器的可并行化生成器
(类模板)

随机数引擎适配器

随机数引擎适配器通过使用另一个随机数引擎作为熵源来生成伪随机数。它们通常用于改变底层引擎的频谱特性。

定义于头文件 <random>
舍弃随机数引擎的部分输出
(类模板)
将随机数引擎的输出打包成指定位数的块
(类模板)
以不同顺序交付随机数引擎的输出
(类模板)

预定义随机数生成器

多个特定的流行算法已预定义。

定义于头文件 <random>
类型 定义
minstd_rand0 (C++11) std:: linear_congruential_engine < std:: uint_fast32_t ,
16807 , 0 , 2147483647 >

1969年由Lewis、Goodman和Miller发现,1988年被Park和Miller采纳为“最小标准”

minstd_rand (C++11)

std:: linear_congruential_engine < std:: uint_fast32_t ,
48271 , 0 , 2147483647 >
更新的“最小标准”,1993年由Park、Miller和Stockmeyer推荐

mt19937 (C++11)

std:: mersenne_twister_engine < std:: uint_fast32_t ,
32 , 624 , 397 , 31 ,
0x9908b0df , 11 ,
0xffffffff , 7 ,
0x9d2c5680 , 15 ,
0xefc60000 , 18 , 1812433253 >
松本和西村设计的32位梅森旋转算法,1998年

mt19937_64 (C++11)

std:: mersenne_twister_engine < std:: uint_fast64_t ,
64 , 312 , 156 , 31 ,
0xb5026f5aa96619e9 , 29 ,
0x5555555555555555 , 17 ,
0x71d67fffeda60000 , 37 ,
0xfff7eee000000000 , 43 ,
6364136223846793005 >
松本和西村设计的64位梅森旋转算法,2000年

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 >

Martin Lüscher和Fred James设计的24位RANLUX生成器,1994年

ranlux48 (C++11) std:: discard_block_engine < std:: ranlux48_base , 389 , 11 >

Martin Lüscher和Fred James设计的48位RANLUX生成器,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 <

非确定性随机数

std::random_device 是一个非确定性均匀随机位生成器,尽管在缺乏非确定性随机数生成支持的情况下,允许实现使用伪随机数引擎来实现 std::random_device

使用硬件熵源的非确定性随机数生成器
(类)

随机数分布

随机数分布对URBG的输出进行后处理,使得最终输出按照已定义的统计概率密度函数进行分布。

随机数分布满足 RandomNumberDistribution 要求。

定义于头文件 <random>
均匀分布
生成在范围上均匀分布的整数值
(类模板)
生成在范围上均匀分布的实数值
(类模板)
伯努利分布
生成基于 伯努利分布 bool
(类)
生成基于 二项分布 的整数值
(类模板)
生成基于 负二项分布 的整数值
(类模板)
生成基于 几何分布 的整数值
(类模板)
泊松分布
生成基于 泊松分布 的整数值
(类模板)
生成基于 指数分布 的实数值
(类模板)
生成基于 伽马分布 的实数值
(类模板)
生成基于 威布尔分布 的实数值
(类模板)
生成基于 极值分布 的实数值
(类模板)
正态分布
生成基于 标准正态(高斯)分布 的实数值
(类模板)
生成基于 对数正态分布 的实数值
(类模板)
生成基于 卡方分布 的实数值
(类模板)
生成基于 柯西分布 的实数值
(类模板)
生成基于 F分布 的实数值
(类模板) <span class="editsection noprint plainlinks

工具函数

定义于头文件 <random>
在区间 [ 0 , 1 ) 上均匀生成指定精度的实数值
(函数模板)
(C++11)
通用偏置消除的加扰种子序列生成器
(类)

随机数算法

定义于头文件 <random>
使用均匀随机位生成器填充范围内的随机数
(算法函数对象)

C 随机库

除了上述介绍的引擎和分布类型外,C语言随机库中的函数和常量也可用(但不推荐使用):

定义于头文件 <cstdlib>
生成伪随机数
(函数)
初始化伪随机数生成器
(函数)
std::rand 所能生成的最大值
(宏常量)

示例

#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <random>
#include <string>
int main()
{
    // 如果可用,使用真实随机值进行种子初始化
    std::random_device r;
    // 在1到6之间随机选择均值
    std::default_random_engine e1(r());
    std::uniform_int_distribution<int> uniform_dist(1, 6);
    int mean = uniform_dist(e1);
    std::cout << "随机选择的均值: " << mean << '\n';
    // 围绕该均值生成正态分布
    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 << "围绕 " << mean << " 的正态分布:\n"
              << std::fixed << std::setprecision(1);
    for (auto [x, y] : hist)
        std::cout << std::setw(2) << x << ' ' << std::string(y / 200, '*') << '\n';
}

可能的输出:

随机选择的均值: 4
围绕 4 的正态分布:
-4
-3
-2
-1
 0 *
 1 ***
 2 ******
 3 ********
 4 *********
 5 ********
 6 ******
 7 ***
 8 *
 9
10
11
12

参见

C 文档 关于 伪随机数生成