• C++中随机数的生成


    1.随机数由生成器和分布器结合产生

    生成器generator:能够产生离散的等可能分布数值
    分布器distributions: 能够把generator产生的均匀分布值映射到其他常见分布,如均匀分布uniform,正态分布normal,二项分布binomial,泊松分布poisson

    2.分布器利用运算符()产生随机数,要传入一个generator对象作为参数

    1 std::default_random_engine generator;  
    2 std::uniform_int_distribution<int> dis(0,100);  
    3 for(int i=0;i<5;i++)  
    4 {  
    5     std::cout<<dis(generator)<<std::endl;  
    6 }

     如果嫌每次调用都要传入generator对象麻烦,可以使用std::bind,要包含头文件functional

    auto dice = std::bind(distribution,generator)以后就可以直接调用dice()产生复合均匀分布的随机数。
    但是多次运行上例会发现每次产生的随机数序列都一样,因为没有设定种子(同cstdlib库中的rand和srand关系)
    1 std::default_random_engine generator;  
    2 std::uniform_int_distribution<int> dis(0,100);  
    3 auto dice= std::bind(dis,generator);  
    4 for(int i=0;i<5;i++)  
    5 {  
    6     std::cout<<dice()<<std::endl;  
    7 }  

    3.种子

            除了random_device生成器(真随机数生成器或叫f非确定性随机数生成器)以外(linux中有效,windows下其实也是伪随机),所有在库中定义的随机数引擎都是伪随机数生成器,他们都利用了特定的算法实现,这些生成器都需要一个种子。种子可以是一个数值,或者是一个带有generate成员函数的对象。简单的应用中,用time作种子即可。
    说明:如果不设定种子,那么产生的随机数序列每次都一样,如上代码,产生5个1到6之间的随机数,但是每次都是82 13 91 84 12
    改为如下代码,可以使每次产生的随机数序列不同:
    1  std::default_random_engine generator(time(NULL));  
    2 std::uniform_int_distribution<int> dis(0,100);  
    3 auto dice= std::bind(dis,generator);  
    4 for(int i=0;i<5;i++)  
    5 {  
    6     std::cout<<dice()<<std::endl;  
    7 }  

    4.关于生成器

            C++11标准提供了三个生成器模版类可以实例化为生成器,但需要有一定的数学功底才懂得每个模版参数的意义,可参照算法出处的论文。
    这三个生成器类模版为:
    linear_congruential_engine 线性同余法
    mersenne_twister_engine 梅森旋转法
    substract_with_carry_engine滞后Fibonacci
    线性同余法举例
    template <class UIntType, UIntType a, UIntType c, UIntType m>
    class linear_congruential_engine;
    第一个参数:生成器类型unsigned int,unsigned long等
    第二到第四个参数:是线性同余法公递推公式Nj+i =(AxNj+C) (mod M)里的三个常数值A,C,M
    要求:如果m不为0,a,c的值要小于m
    如一会介绍的常用生成器:
    1 typedef linear_congruential<unsigned long, 16807, 0, 2147483647> minstd_rand0;  
    1 typedef linear_congruential<unsigned long, 48271, 0, 2147483647> minstd_rand;  
    可见如果自己实例化模版类很麻烦,需要很强的数序知识,所以有几个常用的几个模版实例化生成器,他们都是需要一个种子参数就可以:
    4.1线性同余法:
    minstd_rand()
    minstd_rand0
    利用适配器变种后的线性同余法
    knuth_b     minstd_rand0 with shuffle_order_engine
    4.2梅森旋转法:
    default_random_engine()
    mt19937
    mt19937_64
    4.3滞后Fibonacci法
    ranlux24_base
    ranlux48_base
    利用适配器变种后的滞后Fibonacci法:
    ranlux24              ranlux24_base with discard_block_engine
    ranlux48              ranlux48_base with discard_block_engine
     
    三个适配器:discard_block_engine     shuffle_order_engine   independent_bits_engine

    5.关于分布器

            易知,如果只用generator配上seed只能产生离散的等可能分布,产生的数值在generator的min和max之间,并且结果都是UIntType的值。无法很好的控制产生数值的分布区间和分布概率。如果要实现这种功能就要用到分布器。
    作用1:改变生成类型,利用模版参数
    作用2:改变值区间,利用实例构造函数参数。或其响应的成员函数设置参数。
    作用3:改变概率分布,选用不同的分布器类型
    5.1均匀分布:
    uniform_int_distribution           整数均匀分布
    uniform_real_distribution         浮点数均匀分布
    5.2伯努利类型分布:(仅有yes/no两种结果,概率一个p,一个1-p)
    bernoulli_distribution     伯努利分布
    binomial_distribution      二项分布
    geometry_distribution     几何分布
    negative_biomial_distribution   负二项分布
    5.3 Rate-based distributions: 
    poisson_distribution  泊松分布
    exponential_distribution 指数分布
    gamma_distribution 伽马分布
     weibull_distribution 威布尔分布
    extreme_value_distribution 极值分布
    5.4正态分布相关:
    normal_distribution         正态分布
    chi_squared_distribution 卡方分布
    cauchy_distribution        柯西分布
    fisher_f_distribution       费歇尔F分布
    student_t_distribution  t分布
    5.5分段分布相关:
    discrete_distribution 离散分布
    piecewise_constant_distribution 分段常数分布
    piecewise_linear_distribution 分段线性分布
  • 相关阅读:
    Vue项目搭建及原理三
    Vue项目搭建及原理一
    JS Cookie丢失问题
    1027 Colors in Mars
    1028 List Sorting
    1029 Median
    1030 Travel Plan
    1031 Hello World for U
    1032 Sharing
    1033 To Fill or Not to Fill
  • 原文地址:https://www.cnblogs.com/cynthia-dcg/p/6225914.html
Copyright © 2020-2023  润新知