ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C++ 之 伪随机数生成 <random>

2021-04-27 15:32:59  阅读:292  来源: 互联网

标签:int random 生成器 value MT C++ 随机数 distribution


C++ 标准库提供了生成随机和伪随机数的类。这些类包括:

  • 随机数生成类:生成均匀分布整数序列的伪随机数生成器,包括随机数引擎、随机数引擎适配器以及预定义随机数生成器。
  • 随机数分布类:将生成器生成的数字序列转换为遵循特定随机变量分布(如均匀分布、正态或泊松分布)的数字序列的对象。

随机数引擎

随机数引擎可以以种子数据为熵源生成伪随机数。

随机种子:初始化随机数生成器,然后利用算法不停迭代产生随机数。最简单的使用方式便是将其作为第一个随机数产生下一个随机数。

类模板作用
linear_congruential_engine实现线性同余算法
mersenne_twister_engine实现梅森缠绕器算法
subtract_with_carry_engine实现带进位减(一种延迟斐波那契)算法

其中线性同余引擎一般地快,并对状态的存储要求非常小。延迟斐波那契生成器在无先进算术指令集的处理器上非常快,但状态存储较为庞大,有时有不太想要的谱特性。梅森缠绕器较慢且拥有较大的状态存储要求,但只要有正确的参数,就会有最长的的不可重复序列,且拥有最想要的谱特性

这里介绍一下线性同余引擎和梅森缠绕器的详细实现过程。

线性同余算法

线性同余算法的实现较为简单,数学表达如下:

X n + 1 = mod ( ( a ∗ X n + b ) , c ) X_{n+1} = \text{mod} \left(\left(a*X_n+b\right), c\right) Xn+1​=mod((a∗Xn​+b),c)

但是其参数 a,b,c 需要满足一定条件,这里给出网上的一种C++代码实现如下:

static uint32 prngState = 0;
​
uint32 init_rand(uint32 seed)
{
    //Seed the pseudo-random number generator
    prngState += seed;
​
    //Successful processing
    return SUCCESS;
}
​
uint32 _rand(void)
{
    uint32 value;
​
    //Use a linear congruential generator (LCG) to update the state of the PRNG
    prngState *= 1103515245;
    prngState += 12345;
    value = (prngState >> 16) & 0x07FF;
​
    prngState *= 1103515245;
    prngState += 12345;
    value <<= 10;
    value |= (prngState >> 16) & 0x03FF;
​
    prngState *= 1103515245;
    prngState += 12345;
    value <<= 10;
    value |= (prngState >> 16) & 0x03FF;
​
    //Return the random value
    return value;
}

int32 rand_range(int32 min, int32 max)
{
    int32 value;
​
    //Valid parameters?
    if (max > min)
    {
        //Pick up a random value in the given range
        value = min + (_rand() % (max - min + 1));
    }
    else
    {
        //Use default value
        value = min;
    }
​
    //Return the random value
    return value;
}

该代码摘自知乎博文

梅森缠绕器

梅森缠绕器的实现过程较为复杂

  • 第一阶段:初始化,根据随机种子获得初始的梅森旋转链;
  • 第二阶段:根据已有梅森旋转链进行旋转算法获取下一次循环的旋转链;
  • 第三阶段:根据梅森旋转链计算随机数;

其C++代码实现如下:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <time.h>

using namespace std;

bool isInit;
int index;
int MT[624];  //624 * 32 - 31 = 19937

void srand(int seed)
{
    index = 0;
    isInit = 1;
    MT[0] = seed;
    for(int i=1; i<624; i++)
    {
        int t = 1812433253 * (MT[i-1] ^ (MT[i-1] >> 30)) + i;
        MT[i] = t & 0xffffffff;   //取最后的32位
    }
}

void generate()
{
    for(int i=0; i<624; i++)
    {
        // 2^31 = 0x80000000
        // 2^31-1 = 0x7fffffff
        int y = (MT[i] & 0x80000000) + (MT[(i+1) % 624] & 0x7fffffff);
        MT[i] = MT[(i + 397) % 624] ^ (y >> 1);
        if (y & 1)
            MT[i] ^= 2567483615;
    }
}
int rand()
{
    if(!isInit)
        srand((int)time(NULL));
    if(index == 0)
        generate();
    int y = MT[index];
    y = y ^ (y >> 11);
    y = y ^ ((y << 7) & 2636928640);
    y = y ^ ((y << 15) & 4022730752);
    y = y ^ (y >> 18);
    index = (index + 1) % 624;
	return y;  //y即为产生的随机数 
}

int main()
{
    srand(0);  //设置随机种子
    int cnt = 0;
    for(int i=0; i<1000000; i++)  //下面的循环是用来判断随机数的奇偶概率的 
    {
        if(rand() & 1)
            cnt++;
    }
    cout<<cnt / 10000.0<<"%"<<endl;
    return 0;
}

该代码摘自it610网,该博文包含原理解析。

随机数引擎适配器

随机数引擎适配器生成以另一随机数引擎为熵源的伪随机数,以随机数引擎为基础产生过更为多样性的随机序列。

类模板作用
discard_block_engine舍弃随机数引擎的某些输出
independent_bits_engine将一个随机数引擎的输出打包为指定位数的块
shuffle_order_engine以不同顺序发送一个随机数引擎的输出

预定义随机数生成器

如果有需要可以根据上述的随机数引擎和随机数引擎适配器构建属于自己的随机数生成器。同时C++的标准库也提供了需要经典的随机数生成器如下:

类型定义
minstd_rand0std::linear_congruential_engine<std::uint_fast32_t, 16807, 0, 2147483647>
由 Lewis、Goodman 及 Miller 发现于 1969,由 Park 与 Miller 于 1988 采纳为“最小标准”
minstd_randstd::linear_congruential_engine<std::uint_fast32_t, 48271, 0, 2147483647>
较新的“最小标准”,为 Park、 Miller 及 Stockmeyer 于 1993 推荐
mt19937 std::mersenne_twister_engine<std::uint_fast32_t, 32, 624, 397, 31,
                            0x9908b0df, 11,                             
                            0xffffffff, 7,                             
                            0x9d2c5680, 15,                             
                            0xefc60000, 18, 1812433253>
                            32 位梅森缠绕器,由松本与西村设计于 1998
mt19937_64std::mersenne_twister_engine<std::uint_fast64_t, 64, 312, 156, 31,
                            0xb5026f5aa96619e9, 29,
                            0x5555555555555555, 17,
                            0x71d67fffeda60000, 37,
                            0xfff7eee000000000, 43, 6364136223846793005>
                            64 位梅森缠绕器,由松本与西村设计于 2000
ranlux24_basestd::subtract_with_carry_engine<std::uint_fast32_t, 24, 10, 24>
ranlux48_basestd::subtract_with_carry_engine<std::uint_fast64_t, 48, 5, 12>
ranlux24std::discard_block_engine<std::ranlux24_base, 223, 23>
24 位 RANLUX 生成器,由 Martin Lüscher 与 Fred James 设计于 1994
ranlux48std::discard_block_engine<std::ranlux48_base, 389, 11>
48 位 RANLUX 生成器,由 Martin Lüscher 与 Fred James 设计于 1994
knuth_bstd::shuffle_order_engine<std::minstd_rand0, 256>
default_random_engine实现定义

随机数分布

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

均匀分布
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产生费舍尔
student_t_distribution产生学生
采样分布
discrete_distribution产生离散分布上的随机整数
piecewise_constant_distribution产生分布在常子区间上的实数值
piecewise_linear_distribution产生分布在定义的子区间上的实数值

其他工具

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

std::random_device :使用硬件熵源的非确定随机数生成器

std::generate_canonical : 使通过随机数生成器获得的数据均匀分布在 [0, 1) 上

seed_seq :通用的偏差消除的混淆种子序列生成器,通过提高种子的多样性降低随机序列的重复出现

标签:int,random,生成器,value,MT,C++,随机数,distribution
来源: https://blog.csdn.net/Flame_alone/article/details/116176780

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有