<random>
定义随机数生成设备,从而允许创建均匀分布的随机数。
要求
标头:<random>
命名空间: std
注意
<random>
库使用“#include <initializer_list>”语句。
总结
随机数生成器是指可产生伪随机值序列的对象。 可产生在指定范围内均匀分布的值的生成器称为均匀随机数生成器 (URNG)。 如果该类具有某些共同的特点,则将旨在充当 URNG 的类模板称为引擎(将在本文后面对此进行讨论)。 通过将 URNG 作为自变量传递到分布的 operator()
,URNG 可以(通常也会)和分布一起使用,从而产生以该分布定义的方式分布的值。
这些链接将跳转到本文的主要部分:
快速提示
使用 <random>
时,请牢记以下这些提示:
在大多数情况下,URNG 将产生必须由分布形成的原始位。 (一个值得注意的例外是
std::shuffle()
,因为它直接使用 URNG。)无法同时安全地调用 URNG 或分布的单一实例化,因为运行 URNG 或分布是修改操作。 有关详细信息,请参阅 C++ 标准库中的线程安全。
提供了几个引擎的预定义 typedef;如果正在使用引擎,则这是创建 URNG 的首选方法。
对于大多数应用程序而言,最有用的配对是
mt19937
引擎和uniform_int_distribution
,如本文后面的代码示例中所示。
<random>
标头中提供了许多可选选项,其中任何选项都优于过时的 C 运行时函数 rand()
。 有关 rand()
的问题以及 <random>
处理这些不足的方式的信息,请观看此视频。
示例
以下代码示例显示如何生成一些随机数字,本例中有 5 个是使用生成器用非确定性种子生成的。
#include <random>
#include <iostream>
using namespace std;
int main()
{
random_device rd; // non-deterministic generator
mt19937 gen(rd()); // to seed mersenne twister.
// replace the call to rd() with a
// constant value to get repeatable
// results.
for (int i = 0; i < 5; ++i) {
cout << gen() << " "; // print the raw output of the generator.
}
cout << endl;
}
2430338871 3531691818 2723770500 3252414483 3632920437
虽然这些是高质量随机数字并且此程序每次运行时生成的数字都不一样,但它们不一定在有用范围之内。 若要控制范围,应使用均匀分布,如以下代码所示:
#include <random>
#include <iostream>
using namespace std;
int main()
{
random_device rd; // non-deterministic generator
mt19937 gen(rd()); // to seed mersenne twister.
uniform_int_distribution<> dist(1,6); // distribute results between 1 and 6 inclusive.
for (int i = 0; i < 5; ++i) {
cout << dist(gen) << " "; // pass the generator to the distribution.
}
cout << endl;
}
5 1 6 1 2
下一个代码示例显示更为实际的一组用例,即使用均匀分布的随机数生成器随机排列矢量内容和数组内容。
// cl.exe /EHsc /nologo /W4 /MTd
#include <algorithm>
#include <array>
#include <iostream>
#include <random>
#include <string>
#include <vector>
#include <functional> // ref()
using namespace std;
template <typename C> void print(const C& c) {
for (const auto& e : c) {
cout << e << " ";
}
cout << endl;
}
template <class URNG>
void test(URNG& urng) {
// Uniform distribution used with a vector
// Distribution is [-5, 5] inclusive
uniform_int_distribution<int> dist(-5, 5);
vector<int> v;
for (int i = 0; i < 20; ++i) {
v.push_back(dist(urng));
}
cout << "Randomized vector: ";
print(v);
// Shuffle an array
// (Notice that shuffle() takes a URNG, not a distribution)
array<string, 26> arr = { { "H", "He", "Li", "Be", "B", "C", "N", "O", "F",
"Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc",
"Ti", "V", "Cr", "Mn", "Fe" } };
shuffle(arr.begin(), arr.end(), urng);
cout << "Randomized array: ";
print(arr);
cout << "--" << endl;
}
int main()
{
// First run: non-seedable, non-deterministic URNG random_device
// Slower but crypto-secure and non-repeatable.
random_device rd;
cout << "Using random_device URNG:" << endl;
test(rd);
// Second run: simple integer seed, repeatable results
cout << "Using constant-seed mersenne twister URNG:" << endl;
mt19937 engine1(12345);
test(engine1);
// Third run: random_device as a seed, different each run
// (Desirable for most purposes)
cout << "Using non-deterministic-seed mersenne twister URNG:" << endl;
mt19937 engine2(rd());
test(engine2);
// Fourth run: "warm-up" sequence as a seed, different each run
// (Advanced uses, allows more than 32 bits of randomness)
cout << "Using non-deterministic-seed \"warm-up\" sequence mersenne twister URNG:" << endl;
array<unsigned int, mt19937::state_size> seed_data;
generate_n(seed_data.begin(), seed_data.size(), ref(rd));
seed_seq seq(begin(seed_data), end(seed_data));
mt19937 engine3(seq);
test(engine3);
}
Using random_device URNG:
Randomized vector: 5 -4 2 3 0 5 -2 0 4 2 -1 2 -4 -3 1 4 4 1 2 -2
Randomized array: O Li V K C Ti N Mg Ne Sc Cl B Cr Mn Ca Al F P Na Be Si Ar Fe S He H
--
Using constant-seed mersenne twister URNG:
Randomized vector: 3 -1 -5 0 0 5 3 -4 -3 -4 1 -3 0 -3 -2 -4 5 1 -1 -1
Randomized array: Al O Ne Si Na Be C N Cr Mn H V F Sc Mg Fe K Ca S Ti B P Ar Cl Li He
--
Using non-deterministic-seed mersenne twister URNG:
Randomized vector: 5 -4 0 2 1 -2 4 4 -4 0 0 4 -5 4 -5 -1 -3 0 0 3
Randomized array: Si Fe Al Ar Na P B Sc H F Mg Li C Ti He N Mn Be O Ca Cr V K Ne Cl S
--
Using non-deterministic-seed "warm-up" sequence mersenne twister URNG:
Randomized vector: -1 3 -2 4 1 3 0 -5 5 -5 0 0 5 0 -3 3 -4 2 5 0
Randomized array: Si C Sc H Na O S Cr K Li Al Ti Cl B Mn He Fe Ne Be Ar V P Ca N Mg F
--
此代码使用测试模板函数演示了两种不同的随机化过程(随机化整数矢量和随机排列索引数据的数组)。 首次调用测试函数时,使用安全加密的、非确定性的、不可设定种子的、不可重复的 URNG random_device
。 第二次测试运行将 mersenne_twister_engine
用作 URNG,以及确定性的 32 位常量种子,这意味着结果是可重复的。 第三次测试运行使用来自 mersenne_twister_engine
的 32 位非确定性结果设定 random_device
的种子。 第四次测试运行通过使用以 random_device
结果填充的种子序列对此进行扩展,这可有效地提供超过 32 位的非确定性随机性(但仍非安全加密的)。 有关详细信息,请继续阅读。
分类列表
均匀随机数生成器
通常根据这些属性来描述 URNG:
周期长度:重复生成的数字序列所需的迭代数。 越长越好。
性能:生成数字的速度和所需的内存量。 越小越好。
质量:生成的序列与真正的随机数的接近程度。 这通常称为“随机性”。
以下部分列出了 <random>
标头中提供的均匀随机数生成器 (URNG)。
非确定性生成器
random_device
类
通过使用外部设备,生成非确定性的、安全加密的随机序列。 通常用于为引擎设定种子。 低性能,高质量。 有关更多信息,请参见备注。
具有预定义参数的引擎 Typedef
适用于实例化引擎和引擎适配器。 有关详细信息,请参阅引擎和分布。
default_random_engine
默认引擎。typedef mt19937 default_random_engine;
knuth_b
Knuth 引擎。typedef shuffle_order_engine<minstd_rand0, 256> knuth_b;
minstd_rand0
1988 最小标准引擎(Lewis、Goodman 和 Miller,1969)。typedef linear_congruential_engine<unsigned int, 16807, 0, 2147483647> minstd_rand0;
minstd_rand
更新的最小标准引擎minstd_rand0
(Park、Miller 和 Stockmeyer,1993)。typedef linear_congruential_engine<unsigned int, 48271, 0, 2147483647> minstd_rand;
mt19937
32 位梅森旋转引擎(Matsumoto 和 Nishimura,1998)。typedef mersenne_twister_engine< unsigned int, 32, 624, 397, 31, 0x9908b0df, 11, 0xffffffff, 7, 0x9d2c5680, 15, 0xefc60000, 18, 1812433253> mt19937;
mt19937_64
64 位梅森旋转引擎(Matsumoto 和 Nishimura,2000)。typedef mersenne_twister_engine< unsigned long long, 64, 312, 156, 31, 0xb5026f5aa96619e9ULL, 29, 0x5555555555555555ULL, 17, 0x71d67fffeda60000ULL, 37, 0xfff7eee000000000ULL, 43, 6364136223846793005ULL> mt19937_64;
ranlux24
24 位 RANLUX 引擎(Martin Lüscher 和 Fred James,1994 年)。typedef discard_block_engine<ranlux24_base, 223, 23> ranlux24;
ranlux24_base
用作ranlux24
的基础。typedef subtract_with_carry_engine<unsigned int, 24, 10, 24> ranlux24_base;
ranlux48
48 位 RANLUX 引擎(Martin Lüscher 和 Fred James,1994 年)。typedef discard_block_engine<ranlux48_base, 389, 11> ranlux48;
ranlux48_base
用作ranlux48
的基础。typedef subtract_with_carry_engine<unsigned long long, 48, 5, 12> ranlux48_base;
引擎模板
引擎模板将用作独立的 URNG 或传递给引擎适配器的基引擎。 通常,使用预定义引擎 typedef 实例化这些模板引擎并将其传递给分布。 有关详细信息,请参阅引擎和分布部分。
名称 | 描述 |
---|---|
linear_congruential_engine 类 |
通过使用线性同余算法生成随机序列。 最简单且质量最低。 |
mersenne_twister_engine 类 |
通过使用梅森旋转算法生成随机序列。 最复杂且质量最高(random_device 类除外)。 性能非常快。 |
subtract_with_carry_engine 类 |
通过使用带进位减法算法生成随机序列。 linear_congruential_engine 的改进,但是质量和性能都比 mersenne_twister_engine 低得多。 |
引擎适配器模板
引擎适配器是适应其他(基)引擎的模板。 通常,使用预定义引擎 typedef 实例化这些模板引擎并将其传递给分布。 有关详细信息,请参阅引擎和分布部分。
名称 | 描述 |
---|---|
discard_block_engine 类 |
通过丢弃由其基引擎返回的值,生成随机序列。 |
independent_bits_engine 类 |
通过再次从其基引擎返回的值中打包位,生成具有指定位数的随机序列。 |
shuffle_order_engine 类 |
通过对从其基引擎中返回的值进行重新排序,生成随机序列。 |
[引擎模板]
随机数分布
以下部分列出了 <random>
标头中提供的分布。 这些分布是后处理机制,通常将 URNG 输出用作输入并通过定义的统计概率密度函数分布输出。 有关详细信息,请参阅引擎和分布部分。
均匀分布
名称 | 描述 |
---|---|
uniform_int_distribution 类 |
在闭区间 [a, b](包含起始值和结束值)范围内产生均匀整数值分布。 |
uniform_real_distribution 类 |
在半开区间 [a,b)(包含起始值,不包含结束值)范围内产生均匀真(浮点)值分布。 |
generate_canonical |
产生 [0,1)(包含起始值,不包含结束值)上给定精度的真(浮点)值的均匀分布。 |
[随机数分布]
伯努利分布
名称 | 描述 |
---|---|
bernoulli_distribution 类 |
产生 bool 值的伯努利分布。 |
binomial_distribution 类 |
产生整数值的二项式分布。 |
geometric_distribution 类 |
产生整数值的几何分布。 |
negative_binomial_distribution 类 |
产生整数值的负二项式分布。 |
[随机数分布]
正态分布
名称 | 描述 |
---|---|
cauchy_distribution 类 |
产生真(浮点)值的柯西分布。 |
chi_squared_distribution 类 |
产生真(浮点)值的卡方分布。 |
fisher_f_distribution 类 |
产生真(浮点)值的 F 分布(也称为 Snedecor 的 F 分布或 Fisher-Snedecor 分布)。 |
lognormal_distribution 类 |
产生真(浮点)值的对数正态分布。 |
normal_distribution 类 |
产生真(浮点)值的正态(高斯)分布。 |
student_t_distribution 类 |
产生真(浮点)值的学生 t-分布。 |
[随机数分布]
泊松分布
名称 | 描述 |
---|---|
exponential_distribution 类 |
产生真(浮点)值的指数分布。 |
extreme_value_distribution 类 |
产生真(浮点)值的极值分布。 |
gamma_distribution 类 |
产生真(浮点)值的 gamma 分布。 |
poisson_distribution 类 |
产生整数值的泊松分布。 |
weibull_distribution 类 |
产生真(浮点)值的韦伯分布。 |
[随机数分布]
示例分布
名称 | 描述 |
---|---|
discrete_distribution 类 |
产生离散型整数分布。 |
piecewise_constant_distribution 类 |
产生真(浮点)值的分段常数分布。 |
piecewise_linear_distribution 类 |
产生真(浮点)值的分段线性分布。 |
[随机数分布]
实用函数
本部分列出了 <random>
标头中提供的一般实用函数。
名称 | 描述 |
---|---|
seed_seq 类 |
生成无偏混合种子序列。 用于避免随机变量流的复制。 在许多 URNG 从引擎中进行实例化时很有用。 |
运算符
本部分列出了 <random>
标头中提供的运算符。
名称 | 描述 |
---|---|
operator== |
测试运算符左侧的 URNG 是否等于右侧的引擎。 |
operator!= |
测试运算符左侧的 URNG 是否不等于右侧的引擎。 |
operator<< |
将状态信息写入流。 |
operator>> |
从流中提取状态信息。 |
引擎和分布
有关 <random>
中定义的每个类模板类别的信息,请参考以下部分。 这两个类模板类别都采用类型作为参数,并使用共享模板参数名称来描述允许作为实际参数类型的类型的属性,如下所示:
IntType
指示short
、int
、long
、long long
、unsigned short
、unsigned int
、unsigned long
或unsigned long long
。UIntType
指示unsigned short
、unsigned int
、unsigned long
或unsigned long long
。RealType
指示float
、double
或long double
。
引擎
引擎模板和引擎适配器模板是模板,其参数可自定义创建的生成器。
引擎是类或类模板,其实例(生成器)可充当在最小值和最大值之间均匀分布的随机数的源。 通过采用由一些其他的随机数引擎产生的值并对这些值应用某种算法,引擎适配器可提供具有不同随机性属性的值的序列。
每个引擎和引擎适配器都具有以下成员:
typedef
numeric-type
result_type
是生成器operator()
返回的类型。 在实例化时,numeric-type
将作为模板参数传递。result_type operator()
将返回在min()
和max()
之间均匀分布的值。result_type min()
将返回由生成器的operator()
返回的最小值。 引擎适配器使用基引擎的min()
结果。result_type max()
将返回由生成器的operator()
返回的最大值。 当result_type
是整(整数值)型时,max()
是可实际返回的最大值(包括其本身);当result_type
是浮点(真值)型时,max()
是大于所有可返回的值的最小值(不包括其本身)。 引擎适配器使用基引擎的max()
结果。void seed(result_type s)
使用种子值s
为生成器设定种子。 对于引擎,默认参数支持的签名为void seed(result_type s = default_seed)
(引擎适配器定义单独的void seed()
,请参阅下一小节)。template <class Seq> void seed(Seq& q)
使用seed_seq
Seq
为生成器设定种子。具有类似通过调用
result_type x
创建设定了种子的生成器的参数seed(x)
的显式构造函数。具有类似通过调用
seed_seq& seq
创建设定了种子的生成器的参数seed(seq)
的显式构造函数。void discard(unsigned long long count)
有效地调用operator()
count
时间并丢弃每个值。
此外,引擎适配器还支持这些成员(Engine
是引擎适配器的第一个模板参数,用于指定基引擎的类型):
类似从基引擎的默认构造函数初始化生成器的默认构造函数。
具有参数
const Engine& eng
的显式构造函数。 这是为了支持使用基引擎复制构造。具有参数
Engine&& eng
的显式构造函数。 这是为了支持使用基引擎移动构造。使用基引擎的默认种子值初始化生成器的
void seed()
。返回用于构造生成器的基引擎的
const Engine& base()
属性函数。
每个引擎都会保留状态,该状态可确定通过对 operator()
的后续调用将生成的值的序列。 通过使用 operator==
和 operator!=
,可比较从同一类型的引擎中实例化的两个生成器的状态。 如果两个状态的比较结果相等,则它们将生成同一序列的值。 通过使用生成器的 operator<<
,可将对象的状态作为 32 位无符号的值的序列保存到流中。 保存状态并不会更改状态。 通过使用 operator>>
,可将保存的状态读取到从同一类型的引擎实例化的生成器中。
分发
随机数分布是类或类模板,其实例可将从引擎中获得的均匀分布的随机数的流转换为具有特殊分布的随机数的流。 每个分布都具有以下成员:
typedef
numeric-type
result_type
是分布operator()
区返回的类型。 在实例化时,numeric-type
将作为模板参数传递。通过将
gen
用作均匀分布的随机值的源和存储的分布参数,template <class URNG> result_type operator()(URNG& gen)
可返回根据分布的定义分布的值。通过将
template <class URNG> result_type operator()(URNG& gen, param_type p)
用作均匀分布的随机值的源和参数结构gen
,p
可返回根据分布的定义分布的值。typedef
unspecified-type
param_type
是可选传递给operator()
的参数包,用于代替存储的参数来生成其返回值。const param&
构造函数从其参数中初始化存储的参数。param_type param() const
将获取存储的参数。void param(const param_type&)
将从其参数中设置存储的参数。result_type min()
将返回由分布的operator()
返回的最小值。result_type max()
将返回由分布的operator()
返回的最大值。 当result_type
是整(整数值)型时,max()
是可实际返回的最大值(包括其本身);当result_type
是浮点(真值)型时,max()
是大于所有可返回的值的最小值(不包括其本身)。void reset()
将丢弃所有缓存的值,以便下一个对operator()
的调用的结果不取决于在调用之前从引擎获得的任何值。
参数结构是指存储分布所需的所有参数的对象。 它包含:
typedef
distribution-type
distribution_type
,它是其分布的类型。一个或多个采用与分布构造函数所采用的参数列表相同的构造函数。
与分布相同的参数访问函数。
相等和不相等比较运算符。
有关详细信息,请参阅本文之前链接的此子主题下面的参考子主题。
备注
Visual Studio 中存在两个非常有用的 URNG(mt19937
和 random_device
),如此比较表中所示:
URNG | 快速 | 安全加密 | 可设定种子 | 具有确定性 |
---|---|---|---|---|
mt19937 |
是 | No | 是 | *是 |
random_device |
No | 是 | 否 | 否 |
* 在提供了已知种子的情况下。
虽然 ISO C++ 标准不需要对 random_device
进行安全加密,但是在 Visual Studio 中,会对其实现安全加密。 (术语“加密安全”并不意味着保证,而是指给定随机化算法提供的最低熵水平,因此也指可预测性水平。有关详细信息,请参阅维基百科文章加密安全伪随机数生成器)。因为 ISO C++ 标准不要求这样做,所以其他平台可以将 random_device
实现为简单的伪随机数生成器(不是加密安全的),并且可能只适合作为另一个生成器的种子源。 在跨平台代码中使用 random_device
时,请查看适用于这些平台的文档。
根据定义,random_device
结果是不可复制的,而且副作用是,它的运行速度可能会显著慢于其他 URNG。 虽然你可能希望通过对 random_device
的调用来为应用程序设定种子,但大多数不需要进行安全加密的应用程序都使用 mt19937
或类似引擎,如代码示例中所示。