c++11起推荐用std::uniform_int_distribution配合std::mt19937引擎生成均匀分布整数,避免rand()取模导致的偏差;范围是闭区间[a,b],需用独立引擎实例保障线程安全。

用 std::uniform_int_distribution 生成整数范围随机数
直接用 rand() 取模(比如 rand() % 10 + 1)会导致分布不均,尤其当 RAND_MAX 不是范围长度的整数倍时——低值出现概率明显偏高。C++11 起标准推荐用 std::uniform_int_distribution 配合真随机引擎。
关键点:必须用一个可变状态的引擎(如 std::mt19937),不能重复用同一个种子;分布对象可复用,不必每次新建。
- 引擎初始化建议用
std::random_device当种子:std::mt19937 gen{std::random_device{}()} - 分布对象声明一次即可:
std::uniform_int_distribution<int> dist(1, 6)</int>表示 [1,6] 闭区间 - 生成值写法:
int x = dist(gen)—— 注意不是dist(gen()) - 若需多线程安全,每个线程应持有独立的
gen实例,dist可共享
浮点数范围怎么搞:用 std::uniform_real_distribution
整数分布只管离散值,要 [0.0, 1.0) 或 [-5.5, 10.2] 这类连续范围,必须换 std::uniform_real_distribution。它默认模板参数是 double,但可显式指定 float 以节省空间或匹配计算精度需求。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 开闭性固定:
std::uniform_real_distribution<double>(a, b)</double>生成的是 [a, b) 半开区间,不是 [a,b] - 若真需要闭区间 [a,b],得手动处理边界,比如对生成值做
std::min(b, std::max(a, val)),但通常没必要 - 引擎仍用
std::mt19937不行——它输出整数,必须用std::mt19937_64或std::default_random_engine,后者底层适配更好 - 性能上,浮点分布比整数分布略慢,但差异微乎其微,不用为此降级到
rand()
为什么别碰 rand() 和 srand(time(0))
老代码里常见 srand(time(0)); int x = rand() % 100 + 1;,这在现代 C++ 中属于技术债。问题不止是分布偏差:
-
rand()通常只有 15 位有效随机比特(RAND_MAX常为 32767),而std::mt19937是 32 位全熵 -
time(0)秒级精度,同一秒内多次运行程序会得到完全相同的随机序列 -
rand()是全局状态,多线程调用会竞态,且无法隔离不同逻辑的随机流 - 某些平台(如 macOS)
rand()实现极差,低位几乎不变化
跨平台兼容性要注意的细节
Windows 和 Linux 下 std::random_device 行为可能不同:Linux 通常读 /dev/urandom,Windows 用 CryptoAPI,都算可靠;但 MinGW-w64 的旧版本曾把 std::random_device 退化成伪随机,此时应 fallback 到时间+线程 ID 混合种子。
- 检查是否真随机:
std::random_device{}.entropy() > 0.0,返回 0 表示确定性回退 - 避免把
std::random_device当作“一次性种子发生器”反复调用——它资源有限,应只取一次种子 - 若目标平台已知无硬件随机源(如嵌入式裸机),就明确用
std::seed_seq构造种子,比如:std::seed_seq seq{12345, 67890, static_cast<unsigned int>(time(0))}</unsigned>
真正麻烦的从来不是“怎么写一行生成随机数”,而是让分布严格均匀、线程安全、跨平台一致——这些细节漏掉一个,测试时看不出,压测或用户环境里才爆雷。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










