直接用 == 比较 float/double 几乎总是错的,因浮点数是二进制近似表示,0.1+0.2==0.3 必然为 false;编译器、硬件、平台差异及 nan/-0.0 等边界进一步加剧问题。

直接用 == 比较 float/double 几乎总是错的
因为浮点数在内存中是二进制近似表示,像 0.1 这样的十进制小数根本无法精确存储——它在 double 中实际是 0.10000000000000000555...。所以 0.1 + 0.2 == 0.3 在 C++ 中几乎必然返回 false,这不是 bug,而是 IEEE 754 标准的必然结果。
编译器、硬件和计算路径都会影响比特位
即使两个变量来自同一行赋值,也不能保证它们的二进制位完全一致:
- x87 FPU 寄存器默认使用 80 位扩展精度,中间结果可能比
double(64 位)多保留几位,一旦写回内存就发生截断,导致两次“相同”计算产生不同比特 - 编译器优化(如
-ffast-math)可能重排运算顺序,改变舍入点 - 不同平台(x86 vs ARM)、不同标准库实现,对
sin、log等函数的精度处理也略有差异
std::numeric_limits::epsilon() 不是万能阈值
std::numeric_limits<double>::epsilon()</double> 返回的是 1.0 附近的最小可分辨差值(约 2.22e-16),但它不适用于其他数量级:
- 比较
1e10和1e10 + 1时,真正有效的容差应是epsilon * 1e10 ≈ 2.22e-6,而非2.22e-16 - 比较
1e-15和0.0时,epsilon太小,反而会因浮点下溢或舍入丢失而失效 - 它不反映计算误差本身——一次
std::sqrt调用的误差可能已达1e-15量级
NaN 和 -0.0 是容易被忽略的边界情况
== 对 NaN 总是返回 false,包括 NaN == NaN;而 -0.0 == 0.0 返回 true,但它们的 bit pattern 不同,某些序列化或哈希场景下会导致不一致。
- 任何含
NaN的比较逻辑若没显式检查,可能静默跳过分支 - 用
std::abs(a - b) 判断时,若 <code>a或b是NaN,结果是false(因为std::abs(NaN)是NaN),但你未必意识到这是 NaN 导致的,而非数值差异 -
-0.0和0.0在大多数数学运算中行为一致,但在除法、signbit、某些格式化输出中表现不同
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











