std::midpoint能防溢出,因其对整型采用a+(b-a)/2等位运算或分段计算,避免(a+b)/2的中间加法溢出;对浮点则用稳健算法防止精度坍塌或inf。

std::midpoint 为什么能防溢出?
因为 std::midpoint 不用 (a + b) / 2 这种先加后除的套路——整数加法溢出就完了。它内部对整型做的是位运算或分段计算(比如 a + (b - a) / 2),天然避开中间值超限;对浮点则用更稳健的算法,避免大数相加导致精度坍塌或 inf。
但它只在 C++20 起可用,且要求两个参数类型相同、可比较、支持算术运算。传 int 和 long long 会编译失败,不是自动提升。
哪些场景必须用 std::midpoint 而不是手写公式?
二分查找边界计算、指针差值取中点、安全插值——这些地方若用 (low + high) / 2,low 和 high 都接近 INT_MAX 时必溢出,结果未定义(可能变负、崩溃或静默错误)。
-
std::midpoint对int、unsigned int、ptrdiff_t、std::byte*等都安全 - 不能用于自定义类型,除非你特化了
std::midpoint的重载(标准没提供) - 浮点类型也支持,但要注意:当
a和b符号相反且绝对值悬殊时,std::midpoint比(a + b) / 2更准(例如std::midpoint(1e30, -1.0)不会丢失-1.0的贡献)
常见误用和编译错误
最常踩的坑是类型不匹配或传了非法指针:
立即学习“C++免费学习笔记(深入)”;
- 传两个不同整型:比如
std::midpoint(10, 100L)→ 编译失败,必须显式转成同类型,如std::midpoint(static_cast<long>(10), 100L)</long> - 传
nullptr或野指针:对指针版本,要求两个指针指向同一数组(或一前一后),否则行为未定义;std::midpoint(nullptr, p)是错的 - 用在非标准布局类型上:比如带虚函数或非 POD 的类指针,编译器可能不接受
- 忘记包含头文件:
#include <numeric></numeric>,否则连函数名都找不到
替代方案与兼容性兜底
如果你卡在 C++17 或更早,没法用 std::midpoint,就得手动防溢出:
- 有符号整数:用
low + (high - low) / 2(确保high >= low) - 无符号整数:同样适用,但注意
high - low是模运算,只要逻辑上high >= low就没问题 - 跨平台安全写法(C++11 起):
static_cast<t>((static_cast<unsigned long>(a) + static_cast<unsigned long>(b)) >> 1)</unsigned></unsigned></t>,但要小心类型宽度和符号转换 - 别用
std::abs做中点修正——它本身可能溢出(如INT_MIN)
真正容易被忽略的是:即使用了 std::midpoint,如果原始数据来自外部(比如网络、文件),仍需校验范围是否合理——函数不负责检查逻辑越界,只保数学安全。










