伪随机数生成

< cpp‎ | numeric
 
 
数值库
常用数学函数
数学特殊函数 (C++17)
数学常数 (C++20)
浮点环境 (C++11)
复数
数值数组
伪随机数生成
编译时有理数算术 (C++11)
数值算法
(C++17)
(C++17)
插值
(C++20)
(C++20)
通用数值运算
(C++11)
位操作
(C++20)
(C++20)
(C++20)
(C++20)
(C++20)
(C++20)
(C++20)
(C++20)
(C++20)
(C++20)
 
 

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

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

URBG 和分布被设计为相互使用以生成随机值。所有随机数引擎都可以指定地播种、序列化和反序列化,以用于可重复的模拟器。

均匀随机位生成器

均匀随机位生成器是函数对象,它返回无符号整数值,并使得每个值在可能结果的范围中拥有(理想上)相等的被返回概率。

所有均匀随机位生成器都满足均匀随机位生成器 (UniformRandomBitGenerator) 要求。 C++20 亦定义 uniform_random_bit_generator 概念。

定义于头文件 <random>
指定类型具备作为均匀随机位生成器的资格
(概念)

随机数引擎

随机数引擎以种子数据为熵源生成伪随机数。数种不同类的伪随机数生成算法实现为能定制的模板。

选择使用何种引擎涉及到多次权衡:线性同余引擎一般地快,并对状态的存储要求非常小。延迟斐波那契生成器在无先进算术指令集的处理器上非常快,但状态存储较为庞大,有时有不太想要的谱特性。梅森缠绕器较慢且拥有较大的状态存储要求,但只要有正确的参数,就会有最长的的不可重复序列,且拥有最想要的谱特性(对于给定的想要的定义)。

定义于头文件 <random>
实现线性同余算法
(类模板)
实现梅森缠绕器算法
(类模板)
实现带进位减(一种延迟斐波那契)算法
(类模板)

随机数引擎适配器

随机数引擎适配器生成以另一随机数引擎为熵源的伪随机数。它们通常用于改换底层引擎的谱特性。

定义于头文件 <random>
舍弃随机数引擎的某些输出
(类模板)
将一个随机数引擎的输出打包为指定位数的块
(类模板)
以不同顺序发送一个随机数引擎的输出
(类模板)

预定义随机数生成器

定义了数个特别的流行算法。

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

由 Lewis、Goodman 及 Miller 发现于 1969,由 Park 与 Miller 于 1988 采纳为“最小标准”

minstd_rand(C++11) std::linear_congruential_engine<std::uint_fast32_t, 48271, 0, 2147483647>

较新的“最小标准”,为 Park、 Miller 及 Stockmeyer 于 1993 推荐

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>

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>
default_random_engine(C++11) 实现定义

非确定随机数

std::random_device 是非确定的均匀随机位生成器,尽管若不支持非确定随机数生成,则允许实现用伪随机数引擎实现 std::random_device

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

随机数分布

随机数分布后处理 URBG 的输出,以使得输出结果按照定义的统计概率密度函数分布。

随机数分布满足随机数分布 (RandomNumberDistribution)

定义于头文件 <random>
均匀分布
产生在一个范围上均匀分布的整数值
(类模板)
产生在一个范围上均匀分布的实数值
(类模板)
伯努利分布
产生伯努利分布上的 bool 值。
(类)
产生二项分布上的整数值。
(类模板)
产生负二项分布上的整数值。
(类模板)
产生几何分布上的整数值。
(类模板)
泊松分布
产生泊松分布上的整数值。
(类模板)
产生指数分布上的实数值。
(类模板)
产生 Γ 分布上的实数值
(类模板)
产生威布尔分布上的实数值。
(类模板)
产生极值分布上的实数值。
(类模板)
正态分布
产生标准正态(高斯)分布上的实数值。
(类模板)
产生对数正态分布上的实数值。
(类模板)
产生 χ2 分布上的实数值。
(类模板)
产生柯西分布上的实数值。
(类模板)
产生费舍尔 F 分布上的实数值。
(类模板)
产生学生 t 分布上的实数值。
(类模板)
采样分布
产生离散分布上的随机整数。
(类模板)
产生分布在常子区间上的实数值。
(类模板)
产生分布在定义的子区间上的实数值。
(类模板)

工具

定义于头文件 <random>
给定精度的均匀分布在 [0, 1) 上的实数值
(函数模板)
(C++11)
通用的偏差消除的混淆种子序列生成器
(类)

C 随机库

除了上述的引擎和分布,来自 C 随机库的函数和常量亦可用,尽管不推荐:

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

示例

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <cmath>
 
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 << "Randomly-chosen mean: " << 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 << "Normal distribution around " << mean << ":\n";
    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/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

参阅