HOWTO · C++

如何在 C++ 中生成一个 0 和 1 之间的随机数

本文演示了如何在 0 和 1 之间创建一个区间随机数的 C++ 方法。

本页内容

要生成一个从 0 开始、但不包括 1 的浮点伪随机值,可将 C++11 随机引擎与 std::uniform_real_distribution<double> 配合使用。示例采用固定种子,因此在同一实现上使用相同的引擎和种子会得到相同的序列。编写新 C++ 代码时使用 <random>;维护旧代码时则保留 std::rand。

使用 C++11 <random> 生成浮点数

包含 <random>,创建一个引擎,并在每次需要生成值时将它传给分布对象。引擎会生成一串伪随机位;分布对象则将这些位映射为指定类型和范围内的值。下面的完整示例会输出五个值。固定种子使程序在同一标准库实现上重复运行时得到相同结果。

#include <iostream>
#include <random>

int main() {
    std::mt19937 engine(2026);
    std::uniform_real_distribution<double> distribution(0.0, 1.0);

    for (int i = 0; i < 5; ++i) {
        std::cout << distribution(engine) << '\n';
    }
}

输出的数字取决于标准库实现。在同一实现上,使用相同的引擎和种子会从相同的序列起点开始。若要使用另一条序列,可以更换种子,或使用 std::random_device 初始化引擎一次;但并非所有系统上的该设备都能提供非确定性熵。

理解输出范围并选择引擎

对于 std::uniform_real_distribution<double>(0.0, 1.0),规定的区间是左闭右开区间:可能返回 0,但不会返回 1。模板参数决定浮点结果类型(float、double 或 long double)。分布对象需要接收一个引擎参数;它本身不是独立的生成器。

引擎决定伪随机序列,种子决定从序列的哪个位置开始。std::mt19937 是广泛使用的标准引擎,其算法有明确规定。如果不在意具体使用哪种引擎,std::default_random_engine 会比较方便;但它的选择由实现定义,因此当你需要在不同标准库之间获得相同序列时,它不太合适。引擎应只播种一次并重复使用;每次生成值前都重新播种可能导致值重复,也会损害序列质量。这些设施适用于模拟、游戏和一般随机行为,但不适合生成加密密钥等秘密值。

仅在维护旧代码时使用 std::rand

旧代码可能会使用在 <cstdlib> 中声明的 std::rand。它会返回从 0 到 RAND_MAX(含端点)的整数。相除前先转换为浮点数,以避免整数除法。例如,内联表达式 static_cast<double>(std::rand()) / (static_cast<double>(RAND_MAX) + 1.0) 可以将该整数缩放到所需范围。

这种缩放会确保结果小于 1,即使 std::rand 返回 RAND_MAX 也是如此。若希望每次运行采用不同序列,可在生成值前调用一次 std::srand,通常使用基于时间的种子;不过重复运行仍可能使用相同种子,而且播种并不会提高生成器的质量。RAND_MAX 由实现决定;与 <random> 相比,std::rand 对引擎和序列的控制能力较弱。新代码应优先使用 C++11 引擎和分布对象;只有在现有接口要求时才使用这个旧式函数。