随机数
程序通常需要一个随机数源。在新标准出现以前,C和C++都依赖rand
函数用来生成随机数。
此函数生成均匀分布的伪随机数,范围在0到一个系统相关的最大值(至少为32767)之间。
rand
函数存在一些问题,比如不同范围的随机数、随机浮点数、非均匀分布的数等。
随机数库
定义在头文件<random>
中的随机数库通过随机数引擎类(random-number engines)
和 随机数分布类(random-number distribution)
来解决这些问题。
作用 | |
---|---|
引擎类 | 生成随机unsigned整数序列 |
分布类 | 使用引擎返回服从特定概率分布的随机数 |
随机数库的使用
#include <random>
#include <ctime>
void test1()
{
default_random_engine e(static_cast<unsigned>(time(nullptr)));//默认随机数引擎,且以当前时间为种子
cout << "e.min() = " << e.min() << endl;
cout << "e.max() = " << e.max() << endl;
uniform_int_distribution<unsigned> u(0, 100);//整型均匀分布,且范围在0~100
cout << "整型均匀分布:0~100" << endl;
for (int i = 0;i < 10;++i) {
cout << u(e) << ends;
}
cout << "\n浮点型均匀分布:0~1" << endl;
uniform_real_distribution<double> ur(0, 1);//浮点型均匀分布,且范围在0~1
for (int i = 0;i < 10;++i) {
cout << ur(e) << ends;
}
}
输出 :
e.min() = 0
e.max() = 4294967295
整型均匀分布:0~100
26 18 81 77 31 58 74 30 90 15
浮点型均匀分布:0~1
0.602874 0.749888 0.406369 0.3374 0.066278 0.378081 0.61525 0.0979531 0.709755 0.608517
默认随机数引擎会生成无符号随机整数,其范围在此为(0,4294967295)。
为了避免每次生成的数都是一样的,需要设置随机种子。
标准库定义了多个随机数引擎类,区别在于性能和随机性质量不同。有关操作见下表:
解释 | |
---|---|
Engine e; | 默认构造,使用默认种子 |
Engine e(s); | 使用整型值s作为种子 |
e.seed(s) | 使用种子s重置引擎的状态 |
e.min()和e.max() | 此引擎可生成的最小值和最大值 |
Engine::result_type | 此引擎生成的结果类型 |
e.discard(u) | 将引擎推进u步,u的类型为unsigned long long |
其他分布类型
除了均匀分布以外,还有其他分布类型。
正态分布
#include <cmath>
void test2()
{
default_random_engine e(static_cast<unsigned>(time(nullptr)));
normal_distribution<> n(4, 1.5);//正态分布n,均值为4,标准差为1.5
vector<unsigned> vec(9);//9个0
for (int i = 0;i < 200;++i) {
unsigned v = lround(n(e));//此处数学描述应为:n(e)服从正态分布N(4,2.25)。
if (v < vec.size()) {
++vec[v];
}
}
for (int i = 0;i < vec.size();++i) {
cout << i << ":" << string(vec[i], '*') << endl;
}
}
结果:
在程序中,使用了正态分布,其均值为4,标准差为1.5,方差为2.25。
由于normal_distribution<>
生成浮点值,所以使用lround
函数四舍五入得到整数。
生成200个随机数,它们以均值4位中心,标准差为1.5。由于是正态分布,我们期望生成的数中99%都在0~8之间。
并且使用一个vector将其下标对应数字出现的次数记录下来。之后对结果打印。
伯努利分布
void test3()
{
default_random_engine e(static_cast<unsigned>(time(nullptr)));
bernoulli_distribution b(0.6);//普通类,而非模板类
vector<unsigned> vec(2);
for (int i = 0;i < 1000;++i) {
++vec[b(e)];
}
cout << "0 出现次数:" << vec[0] << endl;
cout << "1 出现次数:" << vec[1] << endl;
}
结果:
0 出现次数:405
1 出现次数:595
伯努利分布会随机生成0或1。bernoulli_distribution
默认概率为50:50,参数0.6表示其产生1的概率为0.6。
参考资料
《C++ Primer 第5版》