C++怎么生成随机数 C++ rand与mt19937随机数引擎用法【示例】

2026-01-28 00:00:00 作者:裘德小鎮的故事
rand() 因随机质量差、模偏差、线程不安全且依赖全局状态,现已不推荐使用;应改用 std::mt19937 配合 std::random_device 和分布类,确保线程安全与高质量随机性。

rand() 为什么现在不推荐用了

因为 rand() 是 C 标准库遗留函数,生成的伪随机数质量差、范围固定(RAND_MAX 通常只有 32767),且无法控制分布类型。更严重的是,它依赖全局状态,多线程下不安全,且种子只能用 srand() 设一次——哪怕你反复调用 srand(time(nullptr)),在快速循环中极易得到重复序列。

常见错误现象:rand() % 100 看似生成 0–99,但若 RAND_MAX 不是 100 的整数倍,低值概率会略高(模偏差);用 time(nullptr) 在一秒内多次初始化,结果全一样。

  • 不要

    rand() 做密码学、模拟、游戏逻辑等对随机性有要求的场景
  • 不要在循环里反复调用 srand()
  • 避免 rand() % N,改用 rand() / (RAND_MAX / N + 1)(仍不推荐,仅作对比理解)

mt19937 是什么,怎么正确初始化

std::mt19937 是 C++11 引入的 Mersenne Twister 引擎,周期长(2¹⁹⁹³⁷−1)、统计性质好、速度快,是当前最常用的标准随机引擎。但它本身只产生均匀分布的 32 位无符号整数(uint32_t),必须配合分布类(如 std::uniform_int_distribution)才能得到指定范围或类型的随机值。

关键点:引擎要独立实例化,不能全局共享;种子应使用 std::random_device 获取真随机熵,而非 time(nullptr)

std::random_device rd;                    // 真随机源(通常读 /dev/urandom 或 CryptGenRandom)
std::mt19937 gen(rd());                   // 用真随机数初始化 mt19937
std::uniform_int_distribution dis(1, 100); // 定义 [1, 100] 均匀分布
int x = dis(gen);                         // 每次调用生成一个 int
  • std::random_device 可能不可用或退化为伪随机(如 MinGW),可用 rd.entropy() == 0 判断
  • 若需可复现结果(如单元测试),可传固定种子:std::mt19937 gen(42)
  • 引擎对象(gen)建议按需创建或作为局部静态变量,避免跨线程共享

生成不同范围和类型的随机数

分布类负责把引擎输出映射到目标范围与类型,不是引擎本身决定的。同一个 std::mt19937 实例可搭配多个分布对象,互不影响。

  • 生成 [0, 1) 的浮点数:std::uniform_real_distribution dis(0.0, 1.0)(注意右边界不包含)
  • 生成 char 范围的字母:std::uniform_int_distribution dis('a', 'z'),再转 char(dis(gen))
  • 生成负数区间 [-10, 10]:std::uniform_int_distribution dis(-10, 10)
  • 避免写 dis(gen) % 10——分布类已处理模偏差,直接用它即可

性能提示:分布对象构造开销小,可复用;引擎调用是主要耗时,但 mt19937 很快,一般无需缓存结果。

多线程环境下怎么安全用

每个线程必须拥有自己的 std::mt19937 实例。共享引擎会导致数据竞争,结果不可预测,且破坏随机性。

典型错误:把 gen 声明为全局或静态变量,然后多线程并发调用 dis(gen)

  • 推荐方式:在线程函数内创建引擎和分布,或使用线程局部存储(thread_local std::mt19937 gen(rd())
  • std::random_device 通常是线程安全的,但某些实现可能不是;若担心,可在主线程生成一个种子,再用它初始化各线程的 mt19937
  • 不要试图用 mutex 保护单个引擎——锁开销大,且违背随机数生成的并发意图

真正容易被忽略的是:即使你只用一个线程,如果对象生命周期管理不当(比如分布对象比引擎先销毁),也可能引发未定义行为。确保分布对象的生存期不长于它所使用的引擎。

猜你喜欢

联络方式:

400 9058 355

邮箱:8955556@qq.com

Q Q:8955556

微信二维码
在线咨询 拨打电话

电话

400 9058 355

微信二维码

微信二维码