uniform_int_distribution构造区间为闭区间[a,b],即包含两端;需搭配复用的随机数引擎使用,模板参数IntType须匹配值范围,负数区间必须用有符号类型。

uniform_int_distribution 构造时传入的区间是闭区间
很多人误以为 uniform_int_distribution 的两个参数是左闭右开(像 std::vector::erase 那样),实际它生成的是包含两端的整数:调用 dist(gen) 可能返回 a 或 b,只要 a ≤ b。如果写成 uniform_int_distribution<int>(1, 10)</int>,结果就是 1~10(含)之间的整数,不是 1~9。
常见错误是“多减一”:比如想生成 [0, n) 就错写成 uniform_int_distribution<int>(0, n-1)</int>——这其实是对的;但若本意是 [1, n] 却写成 (1, n-1),就会漏掉 n。
- 要生成 [a, b](含 a 和 b):直接用
uniform_int_distribution<int>(a, b)</int> - 要生成 [a, b)(含 a、不含 b):用
uniform_int_distribution<int>(a, b-1)</int> - 构造时若
a > b,会抛出std::invalid_argument
必须搭配随机数引擎使用,不能单独调用
uniform_int_distribution 本身不产生随机数,它只是个“转换器”:把引擎输出的均匀浮点/整数,映射到指定整数区间。漏掉引擎或重复创建引擎是高频错误。
典型错误写法:uniform_int_distribution<int>(1,6)(random_device{}())</int>——这里 random_device{} 是临时对象,可能被立即析构,且每次调用都新建引擎,导致重复种子(尤其在循环中)。
立即学习“C++免费学习笔记(深入)”;
- 正确做法:声明一个引擎变量(如
std::mt19937 gen{std::random_device{}()};),再声明分布对象(如uniform_int_distribution<int> dist(1,6);</int>) - 引擎应复用,分布对象也可复用(无状态)
- 不要用
std::rand()配合uniform_int_distribution——它不接受 C 风格函数指针
注意默认模板参数和类型匹配问题
模板参数 IntType 默认是 int,但如果你传入 long long 范围的值(比如 uniform_int_distribution<long long>(LLONG_MIN, LLONG_MAX)</long>),必须显式指定类型,否则编译失败或隐式截断。
另一个坑是:分布对象保存的是你传入的 a 和 b 值的副本,类型由模板参数决定。如果构造时用 int 字面量但范围超限(如 uniform_int_distribution<int>(0, 3000000000)</int>),字面量先溢出,再传给模板,结果未定义。
- 大范围整数务必显式写类型:
uniform_int_distribution<long long>(0LL, 10000000000LL)</long> - 避免用裸数字字面量参与大数运算,优先用带后缀的常量(
1000000000LL) - 分布对象的
min()/max()成员函数返回值类型与模板参数一致,可用于运行时校验
生成负数区间时符号和边界容易混淆
生成 [-5, 5] 和 [-5, -1] 这类负数区间时,有人会下意识写成 uniform_int_distribution<int>(-5, 5)</int> 却怀疑结果“正负不均”——其实完全均匀,只是心理预期偏差。更隐蔽的问题是:当 a 和 b 符号不同,且你用无符号类型作模板参数(比如 unsigned int),会导致负数被强制转为极大正数,进而触发 a > b 异常。
- 负数区间一律用有符号整型模板参数(
int,long等) - 检查
dist.min() 是个低成本防御手段,尤其在参数来自配置或用户输入时 - 如果需要 [-n, n] 对称区间,直接写
uniform_int_distribution<int>(-n, n)</int>,别拆成两段再拼
最易被忽略的是:分布对象内部可能缓存引擎的多次调用结果以提升性能(例如某些实现对 mt19937 做批量抽取),所以即使你只取一个数,引擎状态也可能已前进多步——这在调试或需要可重现序列时要特别留意。


















