C++ 生成随机数

创建时间 2019-04-26
更新时间 2019-07-30

一般来说,网上绝大多数的关于C++生成随机数的文章,写的都是使用C语言的 rand() 来生成的,比如像下面这样:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
    srand(time(NULL)); // use current time as seed for random generator
    int random_variable = rand();
    printf("Random value on [0,%d]: %d\n", RAND_MAX, random_variable);

    // roll a 6-sided die 20 times
    for (int n=0; n != 20; ++n) {
        int x = 7;
        while(x > 6) 
            x = 1 + rand()/((RAND_MAX + 1u)/6); // Note: 1+rand()%6 is biased
        printf("%d ",  x); 
    }
}

可能的输出:

Random value on [0,2147483647]: 448749574
3 1 3 1 4 2 2 1 3 6 4 4 3 1 6 2 3 2 6 1

rand() 生成一个在 [0, RAND_MAX] 之间的伪随机数。使用 srand() 可以设置随机数种子,如果没有设置随机数种子,那么程序每次运行得到的多个随机数应该是相同的。所以一般情况下都会设置当前时间为随机数种子 srand(time(NULL));

这是C语言中产生随机数的方法,C++ 从 C++11 标准加入了产生随机数的标准库 random,如果使用 C++ 产生随机数,可能的代码如下:

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <cmath>

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";
    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

可能的输出:

Randomly-chosen mean: 4
Normal distribution around 4:
-4 
-3 
-2 
-1 
 0 *
 1 ***
 2 ******
 3 ********
 4 *********
 5 ********
 6 ******
 7 ***
 8 *
 9 
10 
11 
12

一般情况下,获取随机数都往往希望从某个区间里,均匀的选取,但是一些情况下,需要模拟随机变量,C++11 标准里有多种随机分布:

  • 均匀分布
  • 伯努利分布
  • 泊松分布
  • 正态分布
  • 抽样分布

不过绝大多数情况下,需要的功能可能如下:

#include <random>
#include <iostream>

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<> dis(1, 6);

    for (int n=0; n<10; ++n)
        //Use dis to transform the random unsigned int generated by gen into an int in [1, 6]
        std::cout << dis(gen) << ' ';
    std::cout << '\n';
}

参考资料