# 随机数的产生
随机数有着广泛的用途。比如测试、游戏、仿真以及安全等领域都需要用到随机数。标准库所提供的多种可供选择的随机数产生器也恰恰反应了随机数应用范 围的多样性。随机数产生器由引擎(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
- C++11 FAQ中文版 - C++11 FAQ
- Stroustrup先生关于中文版的授权许可邮件
- Stroustrup先生关于C++11 FAQ的一些说明
- 关于C++11的一般性的问题
- 您是如何看待C++11的?
- 什么时候C++0x会成为一部正式的标准呢?
- 编译器何时将会实现C++11标准呢?
- 我们何时可以用到新的标准库文件?
- C++0x将提供何种新的语言特性呢?
- C++11会提供哪些新的标准库文件呢?
- C++0x努力要达到的目标有哪些?
- 指导标准委员会的具体设计目标是什么?
- 在哪里可以找到标准委员会的报告?
- 从哪里可以获得有关C++11的学术性和技术性的参考资料?
- 还有哪些地方我可以读到关于 C++0x的资料?
- 有关于C++11的视频吗?
- C++0x难学吗?
- 标准委员会是如何运行的?
- 谁在标准委员会里?
- 实现者应以什么顺序提供C++11特性?
- 将会是C++1x吗?
- 标准中的"concepts"怎么了?
- 有你不喜欢的C++特性吗?
- 关于独立的语言特性的问题
- __cplusplus宏
- alignment(对齐方式)
- 属性(Attributes)
- atomic_operations
- auto – 从初始化中推断数据类型
- C99功能特性
- 枚举类——具有类域和强类型的枚举
- carries_dependency
- 复制和重新抛出异常
- 常量表达式(constexpr)
- decltype – 推断表达式的数据类型
- 控制默认函数——默认或者禁用
- 控制默认函数——移动(move)或者复制(copy)
- 委托构造函数(Delegating constructors)
- 并发性动态初始化和析构
- noexcept – 阻止异常的传播与扩散
- 显式转换操作符
- 扩展整型
- 外部模板声明
- 序列for循环语句
- 返回值类型后置语法
- 类成员的内部初始化
- 继承的构造函数
- 初始化列表
- 内联命名空间
- Lambda表达式
- 用作模板参数的局部类型
- long long(长长整数类型)
- 内存模型
- 预防窄转换
- nullptr——空指针标识
- 对重载(override)的控制: override
- 对重载(override)的控制:final
- POD
- 原生字符串标识
- 右角括号
- 右值引用
- Simple SFINAE rule
- 静态(编译期)断言 — static_assert
- 模板别名(正式的名称为"template typedef")
- 线程本地化存储 (thread_local)
- unicode字符
- 统一初始化的语法和语义
- (广义的)联合体
- 用户定义数据标识(User-defined literals)
- 可变参数模板(Variadic Templates)
- 关于标准库的问题
- abandoning_a_process
- 算法方面的改进
- array
- async()
- atomic_operations
- 条件变量(Condition variables)
- 标准库中容器方面的改进
- std::function 和 std::bind
- std::forward_list
- std::future和std::promise
- 垃圾回收(应用程序二进制接口)
- 无序容器(unordered containers)
- 锁(locks)
- metaprogramming(元编程)and type traits
- 互斥
- 随机数的产生
- 正则表达式(regular expressions)
- 具有作用域的内存分配器
- 共享资源的智能指针——shared_ptr
- smart pointers
- 线程(thread)
- 时间工具程序
- 标准库中的元组(std::tuple)
- unique_ptr
- weak_ptr
- system error