c++11伪随机数生成库:random

mac2024-10-16  57

随机数引擎

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(); 返回随机数引擎潜在生成的最小值。此值等于 0ustatic 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(); 返回随机数引擎潜在生成的最小值。此值等于 0ustatic 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

最新回复(0)