应使用std::uniform_int_distribution配合引擎生成均匀整数随机数;rand()%N存在分布偏差且不跨平台;浮点分布默认左闭右开,需用nextafter包含右端点;多线程须为每线程独立引擎。

用 std::uniform_int_distribution 生成指定范围整数随机数
直接用 rand() 取模会严重偏向小值,且不可控;C++11 起标准推荐用 std::uniform_int_distribution 配合引擎,才能真正均匀。
常见错误是只调用一次 std::random_device 初始化种子,却在循环里反复创建新分布对象——这不必要且可能影响性能。
- 必须先创建一个引擎(如
std::mt19937),再用std::random_device给它喂种子 - 分布对象(
std::uniform_int_distribution<int>)可复用,传入引擎即可生成新数 - 范围闭区间:构造时传
min和max,比如dist(1, 6)生成 1–6(含)
std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution<int> dist(1, 100); int x = dist(gen); // 每次调用都返回新随机数
为什么不能用 rand() % N + M
因为 rand() 返回值范围是 [0, RAND_MAX],而 RAND_MAX 很少是 N 的整数倍。取模后低区间的数概率更高——比如 RAND_MAX == 32767,要生成 [0,9],数字 0–7 出现概率略高于 8–9。
更糟的是:rand() 在很多旧 libc 实现中周期短、低位比特质量差,% 运算还放大了这个问题。
立即学习“C++免费学习笔记(深入)”;
- Windows MSVC 的
RAND_MAX是 32767,Linux glibc 通常是 2147483647,但行为不跨平台 -
srand(time(nullptr))在一秒内多次运行会得到相同种子,不适合快速重跑场景 - 即使加了
srand,也无法修复分布偏差
std::uniform_real_distribution 生成浮点随机数
和整数分布类似,但注意:浮点分布默认是左闭右开区间 [a, b),不是闭区间。如果需要 [0.0, 1.0],得写成 dist(0.0, 1.0000001) 或手动处理边界——更稳妥的做法是用 std::nextafter。
- 常用类型是
float或double,模板参数需显式指定 - 生成 [0.0, 1.0) 直接用
std::uniform_real_distribution<double>(0.0, 1.0) - 若真要包含 1.0,可用
std::uniform_real_distribution<double>(0.0, std::nextafter(1.0, 2.0))
std::uniform_real_distribution<double> d(0.0, 1.0); double r = d(gen); // r ∈ [0.0, 1.0)
多线程下别共享同一个 std::mt19937 引擎
std::mt19937 不是线程安全的:并发调用 operator() 可能破坏内部状态,导致重复序列或崩溃。这不是“大概率出错”,而是未定义行为。
- 每个线程应持有独立引擎实例(可同用一个
std::random_device种子,但建议用不同 seed,比如加线程 ID 哈希) - 不要把引擎放在全局或静态变量里供多线程轮着用
- 若必须集中管理,用
thread_local存储引擎,或改用无状态的随机函数(如 PCG)
容易被忽略的一点:即使你没显式开线程,用了 async / future / OpenMP,也可能触发并发访问。








