C++11中随机数生成器(random)

1 随机数生成器的分类

  1. Uniform random bit generators (URBGs,随机数生成器/随机数引擎): 生成某一类型最小到最大范围内的均匀分布随机数据
  2. Random number distributions(随机数分布类):将URBGs转成某种分布,如,均匀分布,正态分布等

一般随机数生成器和随机数生成类配合使用,去生成随机数据。

2 随机数据引擎

2.1 线性同余法引擎

类的声明,由于实现了operator(),所以他是一个仿函数类。

template<
    class UIntType,  // The result type generated by the generator. The effect is undefined if this is not one of unsigned short, unsigned int, unsigned long, or unsigned long long
    UIntType a,      // the multiplier term
    UIntType c,      // the increment term
    UIntType m       // the modulus term
> class linear_congruential_engine;

random库贴心的帮我们typedef了两个类型,防止我们不知道怎么设置参数 😃

// Discovered in 1969 by Lewis, Goodman and Miller, adopted as "Minimal standard" in 1988 by Park and Miller
using minstd_rand0 = std::linear_congruential_engine<std::uint_fast32_t, 16807, 0, 2147483647>

// Newer "Minimum standard", recommended by Park, Miller, and Stockmeyer in 1993
using minstd_rand = std::linear_congruential_engine<std::uint_fast32_t, 48271, 0, 2147483647>

2.2 梅森旋转法引擎

类的声明,同样也是仿函数类

template<
    class UIntType,
    std::size_t w, std::size_t n, std::size_t m, std::size_t r,
    UIntType a, std::size_t u, UIntType d, std::size_t s,
    UIntType b, std::size_t t,
    UIntType c, std::size_t l, UIntType f
> class mersenne_twister_engine;

typedef的类型

// 32-bit Mersenne Twister by Matsumoto and Nishimura, 1998
using mt19937 = std::mersenne_twister_engine<std::uint_fast32_t, 32, 624, 397, 31,
                             0x9908b0df, 11,
                             0xffffffff, 7,
                             0x9d2c5680, 15,
                             0xefc60000, 18, 1812433253>;

// 64-bit Mersenne Twister by Matsumoto and Nishimura, 2000
using mt19937_64 = std::mersenne_twister_engine<std::uint_fast64_t, 64, 312, 156, 31,
                             0xb5026f5aa96619e9, 29,
                             0x5555555555555555, 17,
                             0x71d67fffeda60000, 37,
                             0xfff7eee000000000, 43, 6364136223846793005>;

2.3 滞后Fibonacci引擎

类的声明,也是反函数类

template<
    class UIntType,
    std::size_t w, std::size_t s, std::size_t r
> class subtract_with_carry_engine;

typedef的类型

using ranlux24_base = std::subtract_with_carry_engine<std::uint_fast32_t, 24, 10, 24>
using ranlux48_base = std::subtract_with_carry_engine<std::uint_fast64_t, 48, 5, 12>

2.4 非确定随机生成器

类的声明

class random_device;

它并不是由某一个数学算法得到的随机序列,而是通过读取文件,读什么文件看具体的实现(Linux可以通过读取/dev/random文件来获取)。文件的内容是随机的,因为文件内容是计算机系统的熵(熵指的是一个系统的混乱程度)。也是当前系统的环境噪声,系统噪音可以通过很多参数来评估,如内存的使用,文件的使用量,不同类型的进程数量等等。Linux的熵来自键盘计时、鼠标移动等。
在没有非确定源(如硬件设备)时他会产生伪随机数,此时每一个random_device的对象会产生相同的随机数序列

例子:

#include <iostream>
#include <random>
 
void demo(std::random_device&& rd)
{
  for(int n = 0; n != 10; ++n) {
    std::cout << rd() << ' ';
  }
  std::cout << '\n';
}
 
int main()
{
  // Note: How the supplied token is handled is implementation-defined!
  // Default token for random_device is usually /dev/urandom on Linux
  demo(std::random_device{});
 
  // Request /dev/random, blocks when entropy is empty
  // Works on libstdc++, ignored in msvc++, might throw on libc++ (as of Nov 2022)
  demo(std::random_device{"/dev/random"});
 
  // Request non-blocking /dev/urandom, ensures that RDRAND is not used
  // Works on libstdc++ and libc++, ignored in msvc++ (as of Nov 2022)
  demo(std::random_device{"/dev/urandom"});
 
  // Request "hw", will use hardware-based random generation like rdrand
  // Works on libstdc++, ignored in msvc++, throws on libc++ (as of Nov 2022)
  demo(std::random_device{"hw"});
}

2.5 默认随机数引擎

std::default_random_engine;    // 由编译器定义

3 随机数适配器

随机数适配器的作用就是对上述引擎产生的随机序列进行修饰和适配。

3.1 std::discard_block_engine

它丢弃由基本引擎产生的一定数量的数据。从每一块大小P由基本引擎生成的适配器只保留R数字,丢弃剩下的。

类声明

template<
    class Engine,
    std::size_t P, std::size_t R
> class discard_block_engine;

typedef的类型

// 24-bit RANLUX generator by Martin Lüscher and Fred James, 1994
using ranlux24 = std::discard_block_engine<std::ranlux24_base, 223, 23>;
// 48-bit RANLUX generator by Martin Lüscher and Fred James, 1994
using ranlux48 = td::discard_block_engine<std::ranlux48_base, 389, 11>;

3.2 std::independent_bits_engine

independent_bits_engine是一个随机数引擎适配器,它产生与包装引擎不同位数的随机数。

类的声明

template<
    class Engine,
    std::size_t W,
    class UIntType
> class independent_bits_engine;

3.3 std::shuffle_order_engine

他会对随机数引擎产生的序列随机重排,并将其保存在大小为k的表中,当有请求是从中选择一个返回,之后使用随机数引擎产生一个随机数填补这个位置。

类的声明

template<
    class Engine,
    std::size_t K
> class shuffle_order_engine;

typedef的类型

using knuth_b = std::shuffle_order_engine<std::minstd_rand0, 256>;

4 随机数分布类

随机数分布类可以将随机数引擎产生的随机数转成特定分布输出,如整型均匀分布(std::uniform_int_distribution):

类的声明

template< class IntType = int >
class uniform_int_distribution;

例子

#include <iostream>
#include <random>
 
int main()
{
    std::random_device rd;  // Will be used to obtain a seed for the random number engine
    std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
    std::uniform_int_distribution<> distrib(1, 6);
 
    // Use distrib to transform the random unsigned int
    // generated by gen into an int in [1, 6]
    for (int n = 0; n != 10; ++n)
        std::cout << distrib(gen) << ' ';
    std::cout << '\n';
}

4.1 均匀分布:

  • uniform_int_distribution 整数均匀分布
  • uniform_real_distribution 浮点数均匀分布

4.2 伯努利类型分布:(仅有yes/no两种结果,概率一个p,一个1-p)

  • bernoulli_distribution 伯努利分布
  • binomial_distribution 二项分布
  • geometry_distribution 几何分布
  • negative_biomial_distribution 负二项分布

4.3 泊松分布:

  • poisson_distribution 泊松分布
  • exponential_distribution指数分布
  • gamma_distribution 伽马分布
  • weibull_distribution 威布尔分布
  • extreme_value_distribution 极值分布

4.4 正态分布相关:

  • normal_distribution 正态分布
  • lognormal_distribution 对数正态分布
  • chi_squared_distribution 卡方分布
  • cauchy_distribution 柯西分布
  • fisher_f_distribution 费歇尔F分布
  • student_t_distribution t分布

4.5 分段分布相关:

  • discrete_distribution离散分布
  • piecewise_constant_distribution分段常数分布
  • piecewise_linear_distribution分段线性分布

5 小工具

5.1 generate_canonical

std::generate_canonical 可以产生[0,1)范围内随机浮点数

类的声明

template< class RealType, std::size_t Bits, class Generator >
RealType generate_canonical( Generator& g );

例子

#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) << ' ';
    }
}

5.2 seed_seq

他可以产生无符号整型范围内的值序列
类的声明

class seed_seq;

例子

#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';
    }
}

输出

4204997637
4246533866
1856049002
1129615051
690460811
1075771511
46783058
3904109078
1534123438
1495905678

6 示例

#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <random>
#include <string>
 
int main()
{
    // Seed with a real random value, if available
    std::random_device r;
 
    // Choose a random mean between 1 and 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';
 
    // Generate a normal distribution around that mean
    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"
              << std::fixed << std::setprecision(1);
    for (auto [x, y] : hist)
        std::cout << std::setw(2) << x << ' ' << std::string(y / 200, '*') << '\n';
}

7 参考

  1. Pseudo-random number generation
  2. c++ 11 random库的简单用法
  3. C++11 随机数学习
  • 0
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值