文章

mt19937

mt19937

wiki 说明

mt19937 是一个随机数生成器类,效用同 rand(),随机数的范围同 unsigned int 类型的取值范围。

其优点是随机数质量高(一个表现为,出现循环的周期更长;其他方面也都至少不逊于 rand()),且速度比 rand() 快很多。使用时需要 #include<random>

mt19937 基于 32 位梅森缠绕器,由松本与西村设计于 1998 年,使用时用其定义一个随机数生成器即可:std::mt19937 myrand(seed)seed 可不填,不填 seed 则会使用默认随机种子。

mt19937 重载了 operator(),需要生成随机数时调用 myrand() 即可返回一个随机数。

另一个类似的生成器是 mt19937_64,基于 64 位梅森缠绕器,由松本与西村设计于 2000 年,使用方式同 mt19937,但随机数范围扩大到了 unsigned long long 类型的取值范围。

random_device

random_device 是一个基于硬件的均匀分布随机数生成器,在熵池耗尽 前可以高速生成随机数。该类在 C++11 定义,需要 random 头文件。由于熵池耗尽后性能急剧下降,所以建议用此方法生成 mt19937 等伪随机数的种子,而不是直接生成。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <bits/stdc++.h>
using namespace std;
int main()
{
    random_device rd;
    mt19937 rand1_32(time(nullptr)); 
    mt19937 rand2_32(rd());
    // [0, 2^32 - 1 = 4294967295 ≈ 4e9]
    mt19937_64 rand1_64(time(nullptr));
    mt19937_64 rand2_64(rd());
    // [0, 2^64 - 1 = 18446744073709551615 ≈ 1.8e19]
    cout << rand1_32() << endl 
         << rand2_32() << endl 
         << rand1_64() << endl 
         << rand2_64() << endl;
    return 0;
}

常用成员函数

  1. 构造函数:
    • mt19937():默认构造函数,使用默认的种子初始化随机数引擎。
    • mt19937(unsigned int seed):使用指定的种子初始化随机数引擎。
  2. 种子操作函数:
    • seed():设置种子值为默认值。
    • seed(unsigned int seed):设置新的种子值。
  3. 随机数生成函数:
    • operator():生成一个 32 位的随机整数。
  4. 辅助函数:
    • discard(unsigned long long z):等同于执行z次operator(),以丢弃z次生成的随机数。
    • min():获取可生成的最小随机数值。
    • max():获取可生成的最大随机数值。

在随机打乱数组中的应用

通常情况下我们使用 STL 库中的 std::random_shuffle(first, last) 函数来打乱一个数组。但是此调用的是 rand() 函数作为随机函数,这受 srand() 种子函数的支配。

于是我们可以使用 std::shuffle(first, last, myrand) 函数,第三个参数应当传入一个产生随机数的函数。

1
2
3
4
5
6
7
8
9
10
11
12
#include <bits/stdc++.h>
using namespace std;
int main()
{
    random_device rd;
    mt19937 rnd(rd());
    vector<int> v = {0, 1, 2, 3, 4, 5};
    shuffle(v.begin(), v.end(), rnd);
    for(auto i : v)
        cout << i << " ";
    return 0;
}
本文由作者按照 CC BY 4.0 进行授权