[C++]C++Primer Chapter 17
17 标准库特殊设施
4 随机数
定义在头文件random中的随机数库通过一组协作的类来生成随机数:
- 随机数引擎类(random-number engines)
- 随机数分布类(random-number distribution)
一个引擎类可以生成unsigned随机数序列,一个分布类使用一个引擎类生成指定类型的、在给定范围内的、服从特定概率分布的随机数。
4.1 随机数引擎和分布
随机数引擎是函数对象类(参见14.8节,第506页),它们定义了一个调用运算符,该运算符不接受参数并返回一个随机unsigned整数。
标准库定义了多个随机数引擎类,区别在于性能和随机性质量不同。每个编译器都会指定其中一个作为default_random_engine类型。
对于大多数场合,随机数引擎的输出是不能直接使用的,这也是为什么称之为原始随机数。问题出在生成的随机数的值范围通常与我们需要的不符,而正确转换随机数的范围是极其困难的。
分布类型和引擎
为了得到在一个指定范围内的数,需要使用一个分布类型的对象
1 |
|
其中 u(0,0)
表示希望得到[0,9]之间的数。
引擎生成一个数值序列
对于随机数发生器来说:即使生成的数看起来是随机的,但对一个给定的发生器,每次运行程序它都会返回相同的数值序列。
1 |
|
上述代码,每次调用都会返回相同的vector,不是我们想要的。
正确的做法如下
1 |
|
将引擎和分布定义为static的,使其在函数调用之间能够保持住状态。
一个给定的随机数发生器一直会生成相同的随机数序列。一个函数如果定义了局部的随机数发生器,应该将其(包括引擎和分布对象)定义为static的。否则,每次调用函数都会生成相同的序列。
设置随机数发生器种子
最常用的方法是调用系统函数time。这个函数定义在头文件ctime中,它返回从一个特定时刻到当前经过了多少秒。函数time接受单个指针参数,它指向用于写入时间的数据结构。如果此指针为空,则函数简单地返回时间
1 |
|
由于time返回以秒计的时间,因此这种方式只适用于生成种子的间隔为秒级或更长的应用。
4.2 其他随机数分布
生成随机实数
使用新标准库设施,可以很容易地获得随机浮点数。我们可以定义一个uniform_real_distribution类型的对象,并让标准库来处理从随机整数到随机浮点数的映射。
使用分布的默认结果类型
分布类型都是模板,具有单一的模板类型参数,表示分布生成的随机数的类型。
每个分布模板都有一个默认模板实参。生成浮点值的分布类型默认生成double值,而生成整型值的分布默认生成int值。由于分布类型只有一个模板参数,因此当我们希望使用默认随机数类型时要记得在模板名之后使用空尖括号。
生成非均匀分布的随机数
除了正确生成在指定范围内的数之外,新标准库的另一个优势是可以生成非均匀分布的随机数。实际上,新标准库定义了20种分布类型,例如normal_distribution,该分布接受一个均值和方差。
bernoulli_distribution类
该类是一个普通类,而不是模板类。此分布总是返回一个bool值。它返回true的概率是一个常数,此概率的默认值是0.5。