zoukankan      html  css  js  c++  java
  • 【基础】伪随机数生成器mt19937

    使用方法

    使用下列代码定义一个以seed为伪随机数种子的uint32范围内的伪随机数生成器:

    mt19937 rnd(seed);
    

    定义完成后,使用下列代码生成若干个uint32范围内的伪随机数,并将其赋值给uint32类型变量r0, r1, r2, r3,它们极大概率互不相同:

    mt19937 rnd(time(nullptr));
    
    void randTest() {
        uint32_t r0 = rnd();
        uint32_t r1 = rnd();
        uint32_t r2 = rnd();
        uint32_t r3 = rnd();
        D1(r0);     //r0 = 1890107454
        D1(r1);     //r1 = 1903163696
        D1(r2);     //r2 = 1307137696
        D1(r3);     //r3 = 1016102494
    }
    

    同理,使用下列代码测试64位版本的伪随机数生成器:

    mt19937_64 rnd(time(nullptr));
    
    void randTest() {
        uint64_t r0 = rnd();
        uint64_t r1 = rnd();
        uint64_t r2 = rnd();
        uint64_t r3 = rnd();
        D1(r0);     //r0 = 16757819831475078962
        D1(r1);     //r1 = 10644585941176734154
        D1(r2);     //r2 = 14550312371103145914
        D1(r3);     //r3 = 16538001574918540854
    }
    

    更强的伪随机数种子

    有些很无聊的人会喜欢uphack使用time(nullptr)的代码,所以可以使用chrono::system_clock::now().time_since_epoch().count()来代替time(nullptr)

    在本地调试时,常常希望复现某个出错的情形,所以使用下面的条件编译进行控制:

    #define TIME chrono::system_clock::now().time_since_epoch().count()
    
    #ifdef LOCAL
    int rnd_seed = 19937;
    #else
    int rnd_seed = TIME;
    #endif // LOCAL
    
    mt19937 rnd(rnd_seed);
    

    生成 ([L,R]) 范围内的随机整数

    转换成double类型后舍入到最近的整数。

    #define TIME chrono::system_clock::now().time_since_epoch().count()
    
    #ifdef LOCAL
    int rnd_seed = 19937;
    #else
    int rnd_seed = TIME;
    #endif // LOCAL
    
    mt19937 rnd(rnd_seed);
    
    int rangeRand(int L, int R) {
        int res = (int)((1.0 * rnd() / UINT_MAX) * (R - L + 1)) + L;
        return res;
    }
    
    void rangeRandTest() {
        map<int, int> M;
        int n = 2000000, L = 1, R = 10;
        for(int i = 1; i <= n; ++i) {
            int t = rangeRand(L, R);
            M[t] += 1;
        }
        int minnum = INF, maxnum = -INF;
        int mincnt = INF, maxcnt = -INF;
        for(auto i : M) {
            printf("%d:%.6f%
    ", i.first, 100.0 * i.second / n);
            cmin(minnum, i.first);
            cmax(maxnum, i.first);
            cmin(mincnt, i.second);
            cmax(maxcnt, i.second);
        }
        D2(minnum, maxnum);
        D2(mincnt, maxcnt);
    }
    

    输出结果如下:

    1:9.978100%
    2:10.036300%
    3:10.015950%
    4:9.996550%
    5:9.984650%
    6:9.980050%
    7:9.985200%
    8:10.000350%
    9:10.012050%
    10:10.010800%
    minnum = 1, maxnum = 10
    mincnt = 199562, maxcnt = 20072
    

    分布非常均匀。注意,每个数字的出现次数是均匀分布,但出现次数的出现次数是正态分布

    洗牌算法 shuffle

    使用方法如下:

    #define TIME chrono::system_clock::now().time_since_epoch().count()
    
    #ifdef LOCAL
    int rnd_seed = 19937;
    #else
    int rnd_seed = TIME;
    #endif // LOCAL
    
    mt19937 rnd(rnd_seed);
    
    void shuffleTest() {
        int n = 100, a[n + 1];
        for(int i = 1; i <= n; ++i) a[i] = i;
        shuffle(a + 1, a + 1 + n, rnd);
        for(int i = 1; i <= n; ++i) {
            printf("%d ", a[i]);
            if(i % 10 == 0)
                putchar('
    ');
        }
    }
    
    //61 13 98 64 5 79 30 65 83 11
    //85 9 88 74 14 19 68 56 70 59
    //29 90 82 7 48 36 75 6 50 26
    //97 28 92 24 1 35 62 77 89 2
    //3 39 71 53 91 52 80 55 58 100
    //38 4 23 32 95 47 86 20 45 43
    //81 60 99 57 33 8 15 37 78 93
    //40 96 17 12 76 27 31 41 51 42
    //84 66 21 87 25 67 10 63 69 94
    //16 46 49 18 54 22 44 73 34 72
    

    注意默认的random_shuffle()不够随机,在严格的题目中容易翻车。

  • 相关阅读:
    【笔记】ubuntu下搜狗输入法的安装(12.04和14.04都会提到,侧重前者)
    【笔记,转载】c++ string与int的转化
    【笔记】关于字符串相加
    【转载】 C++ fstream文件流读写文件操作详解
    【转载】大数据分析的众包平台—Kaggle (如有侵权,请联系我)
    【转载】 生成模型与判别模型
    【杂记】递归缩写
    【笔记】给自己的博客侧栏添加小时钟
    【笔记】改变vim或者终端terminal的光标形状。光标变细了之后看起来爽快多了!
    【笔记】 使用GNU profiler查找性能瓶颈,查看代码中每个函数所消耗的时间
  • 原文地址:https://www.cnblogs.com/purinliang/p/14219276.html
Copyright © 2011-2022 走看看