mt19937 是 C++11 引入的伪随机数生成器,使用 梅森旋转(Mersenne Twister)算法。

相较于 rand 它的周期更长(\(2^19937 -1\)),生成的随机数更加均匀,速度更快,但仍然是可预测的

定义

1
2
3
4
std::mt19937 rng(seed); // 这里 seed 为任意整数
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count()); // 一般用当前时间作为种子

std::mt19937_64 rng(seed); // 64 位版本

调用 rng() 即可生成在 \([0, 2^32 - 1]\) 范围内的随机数,\(64\) 位版本的 rng() 则在 \([0, 2^64 - 1]\) 范围内。

一些成员函数:

  • .seed(unsigned) 重新设置种子。
  • .discard(n) 跳过 \(n\) 个结果。
  • .min().max() 返回随机数的最小值和最大值。

random_device

如果不想使用伪随机,可以使用 std::random_device 来获取硬件随机数。

C++ 标准规定 std::random_device 可以退化为伪随机数

但一般来说,在 Windows,Linux,macOS 上,std::random_device 都是硬件随机数生成器。

可以通过其成员函数 .entropy() 来获取硬件随机数生成器的熵,如果大于 \(0\),一般都是真随机数。

1
2
std::random_device rd;
std::mt19937 rng(rd()); // 用硬件随机数生成器初始化 mt19937

请不要滥用 std::random_device

  1. 它的速度更慢。
  2. 有研究指出,在熵池耗尽后,std::random_device 可能退化为伪随机数,并且性能急剧下降。

关于 的更多内容,读者可以查阅更多资料。

均匀分布

mt19937 还提供了 分布类,用于生成一定范围内均匀分布的随机数。

均匀分布整数

1
2
std::uniform_int_distribution<int> dist(a, b); // [a, b] 范围内均匀分布整数
int x = dist(rng);

均匀分布浮点数

1
2
std::uniform_real_distribution<double> dist(a, b); // [a, b] 范围内均匀分布浮点数
double x = dist(rng);

正态分布

1
2
std::normal_distribution<double> dist(mean, stddev); // 正态分布,mean 为均值,stddev 为标准差
double x = dist(rng);