zoukankan      html  css  js  c++  java
  • C++生成随机数

    C++为随机数提供了两套工具:C风格的和C++风格的。

    C风格

    C为随机数提供的工具是randsrandRAND_MAX,定义在<stdlib.h>中。

    srandrand设置种子,如果不设置,相当于调用过srand(1)rand产生伪随机数,其范围为0RAND_MAXRAND_MAX至少是32767,在MSVC和GCC中这个值都是32767

    伪随机数看似随机,实则是有规律可循的,对于相同的种子值,rand产生的序列完全相同,也就是说无论你给srand一个什么数字,多次运行程序的结果都将相同——除非你给srand的是不同的数字,比如时间。<time.h>中的time函数返回整数表示的系统时间,可用于设置种子。

    如果我们只需要09的随机数,可以把rand的返回值% 10;如果是42233,可以写rand() % 192 + 42。下面的random函数封装了这项工作。注意只有在b - a + 1远小于或整除RAND_MAX时随机数的分布才比较均匀。

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int random(int a, int b)
    {
        return rand() % (b - a + 1) + a;
    }
    
    int main()
    {
        srand(time(NULL));
        printf("RAND_MAX = %d
    ", RAND_MAX);
        for (int i = 0; i < 10; i++)
            printf("%d ", rand());
        printf("
    ");
        int count[10] = {0};
        for (int i = 0; i < 10000; i++)
            count[random(0, 9)]++;
        for (int i = 0; i < 10; i++)
        {
            printf("%d: ", i);
            for (int j = 0; j < count[i] / 10; j++)
                printf("*");
            printf("
    ");
        }
    }
    

    C++风格

    从C++11开始,C++标准规定了随机数设施,包括均匀随机位生成器(Uniform random bit generators,URBG)和随机数分布等,定义在<random>中。

    URBG分为随机数引擎、引擎适配器、预置随机数生成器和非确定随机数生成器4类,通常后两类就够用了。

    标准规定了3种随机数引擎:

    • 线性同余linear_congruential_engine(LCG),时间空间消耗都少;

    • 梅森旋转mersenne_twister_engine(MT),占用较多内存(在PC上可以忽略),计算量较大;

    • 带进位减法(属于滞后斐波那契生成器,LFG)subtract_with_carry_engine,性能与效果折中。

    随机数引擎都需要一个种子,生成的都是伪随机数。

    引擎适配器可以套一个随机数引擎:

    • discard_block_engine在连续若干个伪随机数中选择若干个;

    • independent_bits_engine把位数多的伪随机数压缩成位数少的;

    • shuffle_order_engine把连续若干个伪随机数重排。

    套娃的方式是模板,理论上你还可以用适配器套适配器,不过CPU可能会有意见。

    随机数引擎的模板参数怎么取?标准定义了一些数学家们发现的效果良好的随机数引擎:LCG minstd_rand0minstd_randknuth_b;MT mt19937mt19937_64;LFG ranlux24_baseranlux48_baseranlux24ranlux48。如果你还是无从下手,那就用default_random_engine,编译器的开发者们为你选好了他们认为最合适的,在MSVC中是mt19937,在GCC中是minstd_rand0

    以上工具都生成伪随机数,标准还定义了真·随机数引擎random_device,尽管标准也允许它是伪随机的。如果它是真随机的,那么使用起来它的效果无疑是最好的,但是多次调用后性能会急剧下降,通常只用于生成伪随机数引擎的种子。

    随机数生成器类型都定义了静态方法minmax,返回生成的随机数的范围,以及无参数的函数调用运算符operator(),返回随机数。

    #include <iostream>
    #include <random>
    
    int main()
    {
        auto engine = std::default_random_engine(std::random_device()());
        std::cout << "min = " << engine.min() << "; max = " << engine.max() << std::endl;
        std::cout << "random numbers: ";
        for (int i = 0; i != 10; ++i)
            std::cout << engine() << ' ';
        std::cout << std::endl;
    }
    

    大多数情况下我们不需要minmax范围的整数,而需要一定分布的整数或实数。标准规定了许多随机数分布类型,我数学不好,不太懂这些。

    • 均匀分布uniform_int_distributionuniform_real_distribution

    • 伯努利分布bernoulli_distributionbinomial_distributionnegative_binomial_distributiongeometric_distribution

    • 泊松分布poisson_distributionexponential_distributiongamma_distributionweibull_distributionextreme_value_distribution

    • 正态分布normal_distributionlognormal_distributionchi_squared_distributioncauchy_distributionfisher_f_distributionstudent_t_distribution

    • 抽样分布discrete_distributionpiecewise_constant_distributionpiecewise_linear_distribution

    构造分布实例时传入分布的参数。调用operator()获得结果,参数为随机数引擎。

    #include <iostream>
    #include <random>
    #include <string>
    
    int main()
    {
        auto engine = std::default_random_engine(std::random_device()());
        std::uniform_int_distribution<int> uniform(0, 9);
        int count[10] = {0};
        for (int i = 0; i != 10000; ++i)
            ++count[uniform(engine)];
        for (int i = 0; i != 10; ++i)
            std::cout << i << ": " << std::string(count[i] / 10, '*') << std::endl;
    }
    

    注意,与STL中左闭右开的习惯不同,uniform_int_distribution构造函数接受的参数是闭区间。

    std::shuffle可用于重排容器元素,定义在<algorithm>中:

    template<typename RandomIt, typename URBG>
    void shuffle(RandomIt first, RandomIt last, URBG&& g);
    

    前两个参数为随机存取迭代器(左闭右开),最后一个为随机数引擎。

  • 相关阅读:
    DB2 java.lang.NoClassDefFoundError:com/ibm/db2/jcc/SQLJContext
    JavaScript字符串split方法
    使用 WebSphere Application Server Community
    为DB2数据库创建新用户帐户并为其分配特定特权
    Servlet3.0之一:Servlet3.0新特性介绍
    window下jni调用dll和linux下jni调用so库(转)
    分表分库之三:中间件介绍
    jboss5 启动时报HsqlException:length must be specified in type definition:VARBINARY错误
    J2EE Formbased Authentication
    阻塞队列之七:DelayQueue延时队列
  • 原文地址:https://www.cnblogs.com/jerry-fuyi/p/12728941.html
Copyright © 2011-2022 走看看