rand()不该再用,因其随机数质量差、范围窄(0~32767)、模运算有偏差;应改用C++11 库,组合引擎(如std::mt19937)与分布(如std::uniform_int_distribution),确保高质量、可复现、无偏移的随机数生成。

为什么 rand() 不该再用了
因为 rand() 生成的随机数质量差、范围窄(通常仅 0~32767),且无法控制分布类型。C++11 引入的 库才是现代标准做法,它分离了随机数引擎和分布,更可控、更可复现、也更符合统计需求。
常见错误是直接用 std::random_device 当作“随机数发生器”反复调用——它本意是熵源,可能耗尽或被系统限制调用频次;真正该反复调用的是封装好的引擎(如 std::mt19937)。
- 不要写
std::random_device{}()多次来生成多个数 - 不要用
rand() % N模拟范围——会产生偏差,尤其当RAND_MAX不是N的整数倍时 - 种子只设一次,通常用
std::random_device初始化引擎,而非每次生成都重播种子
生成 [1, 100] 区间整数的正确写法
核心是组合一个引擎(如 std::mt19937)和一个分布(std::uniform_int_distribution):
#include#include int main() { std::random_device rd; // 熵源,只用一次 std::mt19937 gen(rd()); // 引擎,可重复调用 std::uniform_int_distribution dis(1, 100); // 闭区间 [1, 100] for (int i = 0; i < 5; ++i) { std::cout << dis(gen) << '\n'; // 每次调用 dis(gen) 生成一个数 } }
注意:dis(1, 100) 是包含两端的闭区间,不是左闭右开;若需 [0, N),写成 dis(0, N-1) 是错的,应写 dis(0, N-1)?不,应写 dis(0, N-1)?等等——正确写法是 std::uniform_int_distribution 表示 [0, N−1],所以 [0, N) 就等价于 [0, N−1],前提是 N 是整数。
立即学习“C++免费学习笔记(深入)”;
性能上,std::mt19937 比 rand() 快且质量高;若对性能极端敏感(如高频仿真),可考虑 std::minstd_rand 或复用同一个 gen 实例,避免重复构造。
生成浮点随机数:小心 uniform_real_distribution 的边界
std::uniform_real_distribution 默认生成的是 [0.0, 1.0) 区间(左闭右开),不是 [0.0, 1.0]。这是 IEEE 浮点语义决定的——闭区间在浮点下难以严格实现,标准选择保守定义。
- 要 [a, b):用
std::uniform_real_distribution(a, b) - 要 [a, b](数学闭区间):通常靠缩放+截断容忍,或改用整数分布再除以大常量(如
dis(0, 1000000)/1000000.0) - 引擎状态影响结果:同一
gen实例连续调用dis(gen),结果确定且可复现——这对调试和单元测试很关键
若误写成 std::uniform_real_distribution 并期望能取到 1.0,会永远失败。这不是 bug,是设计使然。
如何让随机序列可复现(用于测试/调试)
把 std::random_device 换成固定种子即可:
std::mt19937 gen(42); // 固定种子 42 std::uniform_int_distributiondis(1, 6); std::cout << dis(gen) << '\n'; // 每次运行都输出相同序列
这比依赖系统熵源更适合自动化测试。但注意:不同编译器或标准库版本对同一引擎+种子产生的序列**不一定完全一致**(尤其跨平台),若需绝对可移植,得自己实现或使用已知行为的第三方引擎(如 PCG)。
真正容易被忽略的是:分布对象(dis)本身不保存状态,状态全在引擎里;所以可以安全地在函数内定义分布,但引擎最好复用或传入,避免频繁重建开销。










