文章

C++ Random

C++ Random

C++ 标准库中的 <random> 头文件提供了一组用于生成随机数的工具,涵盖了从简单的均匀分布到复杂的离散分布,为需要随机数的应用程序提供了广泛的选择。

介绍

<random> 库由以下三个主要组件构成:

  • 随机数引擎:生成伪随机数的核心,用于控制生成过程的可重复性和随机性。
  • 随机数分布:控制生成的数值遵循的概率分布类型。
  • 随机数适配器:允许调整引擎行为,如 discard_block 等适配器。

在 C++ 中,随机数生成器(Random Number Generator, RNG)可以分为两大类:

  • 伪随机数生成器:它们使用确定性算法生成看似随机的数列。这些数列在理论上是可预测的,但通常对于大多数应用来说足够随机。
  • 真随机数生成器:它们基于物理过程(如热噪声、放射性衰变等)生成随机数,但 C++ 标准库不直接提供这类生成器。

简单随机数生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <ctime>
#include <cstdlib>

using namespace std;
 
int main ()
{
    int i,j;

    // 设置种子
    srand( (unsigned)time( NULL ) );

    /* 生成 10 个随机数 */
    for( i = 0; i < 10; i++ ){
        // 生成实际的随机数
        j= rand();
        cout <<"随机数: " << j << endl;
    }
    return 0;
} 

常见随机数引擎

引擎描述
std::default_random_engine默认随机数引擎,实现依赖于具体编译器。
std::minstd_rand线性同余引擎,产生均匀的伪随机数序列。
std::mt19937梅森旋转算法,适合通用随机数生成。
std::mt19937_6464 位的梅森旋转算法。
std::ranlux24_base简化的减法进位引擎,用于高质量生成。
std::knuth_bKnuth shuffle 随机数生成器。

常用引擎如 std::mt19937 因为生成速度快且生成质量高,是普遍推荐的随机数生成引擎。生成器还可以使用 seed() 方法指定种子,便于生成可重复的伪随机序列。

随机数分布类型

均匀分布

分布描述
std::uniform_int_distribution生成在某个整数范围内的均匀分布。
std::uniform_real_distribution生成在某个浮点数范围内的均匀分布。
1
2
3
std::mt19937 gen(seed);
std::uniform_int_distribution<int> dist(1, 100); // 生成 1 到 100 间的整数
int random_int = dist(gen);

正态分布

分布描述
std::normal_distribution标准正态分布,中心对称,常用于模拟自然现象。
std::lognormal_distribution对数正态分布。
1
2
3
std::mt19937 gen(seed);
std::normal_distribution<> dist(0, 1); // 平均值为0,标准差为1
double random_normal = dist(gen);

离散分布

分布描述
std::discrete_distribution生成的随机数为一组特定概率的整数。
std::bernoulli_distribution伯努利分布,只生成 true 或 false。
std::binomial_distribution二项分布。
1
2
3
std::mt19937 gen(seed);
std::discrete_distribution<int> dist({40, 10, 50}); // 概率为40%、10%、50%
int random_discrete = dist(gen);

语法

使用<random>库的基本流程如下:

  1. 包含头文件
  2. 创建一个随机数生成器对象
  3. 使用分布类生成随机数

实例

生成基本随机数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <random>

int main() {
    // 使用随机设备创建一个随机种子
    std::random_device rd;
    
    // 使用随机种子初始化 Mersenne Twister 随机数生成器
    std::mt19937 generator(rd());

    // 生成一个随机数
    std::cout << "Random number: " << generator() << std::endl;

    return 0;
}

使用均匀分布

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <random>

int main() {
    // 创建随机数生成器
    std::mt19937 generator;

    // 创建一个均匀分布的随机数生成器,范围从 1 到 10
    std::uniform_int_distribution<int> distribution(1, 10);

    // 生成并打印 5 个随机数
    for (int i = 0; i < 5; ++i) {
        std::cout << "Random number: " << distribution(generator) << std::endl;
    }

    return 0;
}

使用正态分布

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <random>
#include <iomanip>

int main() {
    // 创建随机数生成器
    std::mt19937 generator;

    // 创建一个正态分布的随机数生成器,均值为 0,标准差为 1
    std::normal_distribution<double> distribution(0.0, 1.0);

    // 设置输出格式,保留两位小数
    std::cout << std::fixed << std::setprecision(2);

    // 生成并打印 5 个随机数
    for (int i = 0; i < 5; ++i) {
        std::cout << "Random number: " << distribution(generator) << std::endl;
    }

    return 0;
}

使用mt19937生成不同分布的随机数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <random>

int main() {
    // 1. 设置种子和随机数引擎
    std::random_device rd; // 随机设备产生种子
    std::mt19937 gen(rd()); // 梅森旋转引擎

    // 2. 均匀分布的整数
    std::uniform_int_distribution<> dist_int(1, 100);
    std::cout << "Uniform integer: " << dist_int(gen) << std::endl;

    // 3. 均匀分布的浮点数
    std::uniform_real_distribution<> dist_real(0.0, 1.0);
    std::cout << "Uniform real: " << dist_real(gen) << std::endl;

    // 4. 正态分布
    std::normal_distribution<> dist_normal(0, 1);
    std::cout << "Normal: " << dist_normal(gen) << std::endl;

    // 5. 离散分布
    std::discrete_distribution<> dist_discrete({10, 20, 70});
    std::cout << "Discrete: " << dist_discrete(gen) << std::endl;

    return 0;
}

随机数适配器

随机数适配器允许调整生成行为,主要有两类适配器

  1. std::discard_block_engine:丢弃一定数量的生成值,仅保留指定间隔的值,用于减少随机性。
  2. std::independent_bits_engine:生成指定位数的随机数,便于直接生成二进制数据。
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <random>

int main() {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::discard_block_engine<std::mt19937, 3, 2> discard_engine(gen);
    std::cout << "Discard block random number: " << discard_engine() << std::endl;

    return 0;
}
本文由作者按照 CC BY 4.0 进行授权