随机数的产生

随机数有着广泛的用途。比如测试、游戏、仿真以及安全等领域都需要用到随机数。标准库所提供的多种可供选择的随机数产生器也恰恰反应了随机数应用范 围的多样性。随机数产生器由引擎(engine)和分布(distribution)两部分组成。其中,engine用于产生一个随机数序列或者伪随机数 序列;distribution则将这些数值映射到位于固定范围的某一数学分布中。关于分布的例子有:unifrom_int (所有的整数倍都被以相等的概率产生)以及normal_distribution (分布的概率密度函数曲线呈钟形);每一种分布都处于某一特定的范围之内。例如:

//distribution将产生的随机数映射到整数1..6
uniform_int_distribution<int> one_to_six {1,6}; 

default_random_engine re {};        //默认的engine

如果想获得一个随机数,你可以用一个随机引擎为参数调用distribution来产生一个随机数:

int x = one_to_six(re); // x 是 [1:6]这个范围内的一个随机数

在每次调用的时候都需要提供一个引擎作为参数非常繁琐,所以我们可将引擎和 distribution邦定成一个函数对象,然后直接通过这个函数对象的调用来产生随机数,而不用每次调用都提供参数了。

auto dice {bind(one_to_six,re)}; //  产生一个新的随机数生成器
int x = dice(); // 调用dice函数对象,x是一个分布在 [1:6]范围的随机数

多亏在设计它是对一般性和性能的关注。在这方面,一位专家曾在评价标准库中随机数模块时说道:“在扩充的过程中,每一个随机数库想变成什么”。然而,它很 难真正让一个新手感觉到容易上手。在性能方面,我从没有见过随机数的接口成为性能的瓶颈。另外,我也一直会使用一个简单的随机数生器来教新手(具有一定的 基础)。下面的就是这样的一个可以说明问题的例子。

int rand_int(int low, high);   //按照均匀分布在区间[low: high]中产生一个随机数

然而我们如何实现rand_int()?我们必须在rand_int()中使用dice()之类的函数:

int rand_int(int low, int high)
{   
     static default_random_engine re {};
     using Dist = uniform_int_distribution<int>;
     static Dist uid {};
     return uid(re, Dist::param_type{low,high});
}

关于rand_int()的定义依然是属于“专家级”的,但是应该把关于它的使用安排在C++课程的第一周。

在这里,我们举一个不太琐碎的关于随机数生成器的例子。这个例子中代码的功能是生成和打印一个正态分布。

default_random_engine re;   //默认引擎

normal_distribution<double> nd(31 /* mean */,
      8 /* sigma */);

auto norm = std::bind(nd, re);

vector<int> mn(64);

int main()
{
    for (int i = 0; i<1200; ++i) 
               ++mn[round(norm())]; // 产生随机数

    for (int i = 0; i<mn.size(); ++i) 
           {
        cout << i << '\t';
        for (int j=0; j<mn[i]; ++j) 
                    cout << '*';

                cout << '\n';
    }
}

我运行了一个支持boost::random的版本并把它编辑到C++0x中,然后得到了下面的结果。

0
1
2
3
4 *
5
6
7
8
9 *
10 ***
11 ***
12 ***
13 *****
14 *******
15 ****
16 **********
17 ***********
18 ****************
19 *******************
20 *******************
21 **************************
22 **********************************
23 **********************************************
24 ********************************************
25 *****************************************
26 *********************************************
27 *********************************************************
28 ***************************************************
29 ******************************************************************
30 **********************************************
31 *********************************************************************
32 **********************************************
33 *************************************************************
34 **************************************************************
35 ***************************************
36 ***********************************************
37 **********************************************
38 *********************************************
39 ********************************
40 ********************************************
41 ***********************
42 **************************
43 ******************************
44 *****************
45 *************
46 *********
47 ********
48 *****
49 *****
50 ****
51 ***
52 ***
53 **
54 *
55 *
56
57 *
58
59
60
61
62
63

另外,可以参考以下文献:

  • Standard 26.5: Random number generation