直接用 == 比较两个 double 几乎总失败,因浮点数是二进制近似表示,如 0.1+0.2≠0.3;应改用 abs(a−b)

为什么 == 比较两个 double 总是失败
浮点数在内存中是二进制近似表示,大多数十进制小数(比如 0.1)无法精确存储。直接用 == 判断相等,等于在比两个近似值是否“完全一样”,几乎总为 false。
- 典型错误现象:
0.1 + 0.2 == 0.3返回false,实际值分别是0.30000000000000004和0.29999999999999999 - 正确做法:用差值绝对值小于某个小阈值(epsilon)来判断“足够接近”
- 推荐阈值不是固定
1e-9:对大数要用相对误差,比如abs(a - b) - 标准库没提供通用比较函数,
std::numeric_limits<double>::epsilon()</double>是1.0附近的最小可表示差,不能直接当比较阈值用
std::setprecision 和 std::fixed 只影响输出,不改变数值本身
很多人以为调了 std::setprecision(2) 就能把 3.14159 “变成” 3.14,其实只是打印时截断显示,内存里还是完整精度的值。
- 输出控制示例:
cout 显示 <code>3.14,但后续计算仍用原始值 - 真要截断/四舍五入存值?得手动做:
round(x * 100.0) / 100.0(注意round在<cmath></cmath>中) - 金融计算等场景必须避免浮点:改用整数(单位“分”)或专用库(如
boost::multiprecision)
不同编译器和平台下 float 与 double 的行为差异
x86 架构上,x87 FPU 默认用 80 位扩展精度做中间计算,而 SSE 指令用标准 32/64 位。这会导致同一段代码在不同编译选项下结果不一致。
- 常见现象:开启
-ffast-math或/fp:fast后,double计算结果突然变“不准”或跨平台不一致 - 关键参数:
-mfpmath=sse(GCC)强制用 SSE,关闭 x87 扩展精度;-fexcess-precision=standard禁用中间高精度 - Windows MSVC 默认用 SSE,Linux GCC 默认可能用 x87,所以同样代码在两平台输出不同不是 bug,是实现差异
- 调试时别只信打印值——用
printf("%.17g", x)看完整有效数字,%.6f会掩盖问题
什么时候该放弃 double 改用整数或定点数
不是所有“带小数”的场景都适合浮点。精度失控往往发生在累加、比较、边界判断这三类操作上。
立即学习“C++免费学习笔记(深入)”;
- 计时器、帧率、物理步进:如果单位固定(如毫秒、1/60 秒),用
int64_t存纳秒或 ticks,避免0.016666...累积漂移 - 配置文件读取的“小数”:比如
"timeout: 2.5",解析后立刻转成int毫秒(2500),全程整数运算 - 游戏坐标更新:用
int像素或int毫米,靠增量控制平滑感,而不是靠float插值硬凑 - 别为了“看起来方便”用浮点存钱、ID、版本号、比例因子——这些本质都是离散量
浮点误差不会自动消失,也不会因为用了更高精度类型就彻底解决。最危险的是把“看起来对”当成“逻辑安全”,尤其在条件分支和循环终止判断里漏掉容差,程序就可能卡死或跳过关键逻辑。










