之前写过一篇C语言生成随机数,其中生成随机数的方法自然也可用于C++中,不过C++ 11扩展了生成随机数的方法,我们可以有更多更好的选择了。
随机数的相关类声明都位于<random>
头文件中,完整说明可参考:random,此处选择一些常用的总结一下。文末参考文献中那两篇知乎讨论很有趣,介绍了各种关于随机数的知识,很值得一读。
随机数生成器
一共提供了3种算法的生成器:线性同余法(LCG)、梅森旋转法、Lagged Fibonacci generator(LFG),其中梅森旋转法据说是最好的伪随机数生成算法,在C++中的具体实现类为std::mt19937
和std::mt19937_64
,前者是32位的,后者是64位的。
非确定性随机数生成设备
上面几个随机数生成器的本质都是从一个种子开始,使用某个递推方法生成伪随机数序列,其实还有种随机数生成策略就是利用物理世界中的各种噪声,以此产生所谓的真随机数。std::random_device
就是这样一种机制,具体实现方法Linux和Windows不相同,以Linux为例就是读取/dev/urandom
设备的输出得到的。这个设备中有一个容纳来自各种设备驱动噪声数据的熵池,具体可参考:
/dev/urandom
是/dev/random
的非阻塞版本,会重复利用熵池,保证在熵池为空的时候也会有输出,这以降低随机数可靠性为代价提高了其生成速度。
生成特定分布的随机数
在C语言中,要生成特定分布的随机数并不容易,不过在C++中这就很简单了,C++中提供了各种常用分布的实现,直接调用就可以了。比如最常用的均匀分布的整数:std::uniform_int_distribution
;均匀分布的小数:std::uniform_real_distribution
;正态分布:std::normal_distribution
等。
使用示例
最后举几个实际的例子来说明具体用法。
直接使用random_device
的输出作为随机数:
1 |
|
此方法速度较慢,所以一般并不直接使用。
以random_device
的输出为初始种子,使用梅森旋转法生成[0,99]范围内的整数:
1 | #include <iostream> |
使用std::bind()
是为了让之后调用起来更方便些。此方法就是生成某个区间内均匀分布的整数随机数最常用的方法了,注意区间两端都是闭区间。
以random_device
的输出为初始种子,使用梅森旋转法生成[0.0, 1.0)范围内的小数:
1 | #include <iostream> |
生成[0, 1)区间内任意小数最常用的方法,注意这里是左闭右开区间,不包含1.0的。