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

随机数引擎

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

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值