因为没调用 srand() 初始化随机数种子,rand() 默认基于固定种子(如1)生成相同序列;解决方法是仅在 main() 开头调用 srand(time(nullptr)),或改用 C++11 的 库实现无偏差、线程安全的随机数生成。

为什么 rand() 每次运行都生成一样的数字?
因为没调用 srand() 初始化随机数种子。默认情况下,rand() 基于固定种子(通常是 1)生成序列,所以每次程序重启,输出完全一致。
解决办法是用当前时间做种子:srand(time(nullptr))。注意必须只调用一次,且最好放在 main() 开头。
-
time(nullptr)返回秒级时间戳,适合一般用途;毫秒级需用std::chrono配合srand不支持 - 不要在循环里反复调用
srand(),会导致重复种子、重复随机数 - 多线程环境下
rand()/srand()不安全,每个线程应有自己的状态(见下节)
怎么生成指定范围的整数,比如 [1, 6] 模拟骰子?
直接用 rand() % 6 + 1 看似简单,但有偏差:当 RAND_MAX 不能被 6 整除时,小余数对应的结果概率略高。
更稳妥的做法是拒绝采样(rejection sampling),或直接换用现代 C++ 方案:
立即学习“C++免费学习笔记(深入)”;
- 传统修正写法:
int dice() { int r; do { r = rand(); } while (r > RAND_MAX - RAND_MAX % 6); return r % 6 + 1; } - C++11 起推荐用
:std::uniform_int_distribution配合dist(1, 6); std::mt19937引擎,无偏差、可重复、线程安全
rand() 和 的关键区别在哪?
rand() 是 C 标准库遗留接口,全局状态、不可预测分布、不支持并行; 是 C++11 引入的现代方案,按对象封装状态和分布,行为明确。
-
rand()输出范围固定为[0, RAND_MAX](通常为 32767),上限低且不可配置 -
std::mt19937默认周期 219937−1,远超rand();std::mt1937_64更适合 64 位场景 - 种子类型不同:
srand(unsigned int)vsstd::mt19937{std::random_device{}()}(真随机种子) - 若需可复现结果(如游戏存档、测试),用确定种子初始化
std::mt19937{12345}即可
为什么用 std::random_device 有时返回恒定值?
某些平台(尤其是 Windows MinGW 或旧版 libc++)未正确实现硬件随机数源,std::random_device::entropy() 返回 0,导致连续调用 () 得到相同整数。
这不是 bug,而是规范允许的退化行为——它只保证“尽可能随机”,不保证熵源存在。
- 检查熵值:
std::random_device rd; std::cout —— 若为 0,别依赖它作唯一种子 - 生产环境建议 fallback:用
rd()为主种子,再混入std::chrono::steady_clock::now().time_since_epoch().count() - 单元测试中,直接用固定种子更可控,避免因随机性导致 CI 失败
实际项目里,只要不是维护老代码,就别碰 rand() 和 srand()。现代 C++ 的随机设施写起来稍长一点,但边界清晰、可测、可移植——这点额外代码量,远低于调试偏态分布或线程冲突的成本。











