0.1 + 0.2 != 0.3 的浮点数精度问题如何可靠比较

浮点数直接用==比较会返回false,因二进制表示存在精度误差;应使用误差容差(如1e-10)判断两数之差的绝对值是否小于epsilon。

直接用 == 比较浮点数(如 0.1 + 0.2 == 0.3)会返回 false,这是由二进制浮点表示的固有局限导致的,不是 bug,而是 IEEE 754 标准下的正常现象。可靠比较的关键是**不比绝对相等,而比“足够接近”**。

夸克网页版官方入口 · 极速搜索直达 → 点我进入

使用误差容差(epsilon)进行近似比较

最常用、最直观的方法是定义一个极小的容差值(如 1e-10),判断两数之差的绝对值是否小于它:

  • JavaScript 示例:
    function floatEqual(a, b, epsilon = 1e-10) { return Math.abs(a - b)
    floatEqual(0.1 + 0.2, 0.3)true
  • 容差值需根据场景选择:科学计算可能用 1e-15,UI 或货币场景用 1e-6 更稳妥;过大易误判,过小仍失效
  • 注意:对极大或极小数值,固定 epsilon 可能不合适,此时应考虑相对误差

相对误差比较(兼顾大小数量级)

当操作数可能非常大(如 1e20)或非常接近零时,仅用绝对误差不够鲁棒。更健壮的方式是结合绝对与相对容差:

  • 公式:Math.abs(a - b)
  • 常见组合:设 epsilonAbs = 1e-12(兜底小值)、epsilonRel = 1e-12(比例基准)
  • Python 的 math.isclose(a, b) 默认就采用这种策略,推荐优先使用标准库函数

业务场景中优先转整数或定点运算

对精度敏感的领域(如金融计算),根本解法是**避免浮点中间过程**:

  • 金额统一用“分”为单位,全部用整数运算:10 + 20 === 30(代表 0.10 + 0.20 === 0.30 元)
  • JavaScript 可借助 BigInt 或专用库(如 decimal.js)做高精度十进制运算
  • 输入时立即解析为整数/定点数,全程不走 parseFloat → 运算 → toFi

    xed
    这类易出错链路

调试与验证时善用工具辅助

理解为何出错,比单纯修复更重要:

  • console.log((0.1).toString(2)) 查看二进制表示,发现 0.1 是无限循环二进制小数
  • Number.EPSILON 理解 JS 中可表示的最小间隔(约 2.22e-16),但注意它不等于通用容差
  • 单元测试中不要写 expect(0.1 + 0.2).toBe(0.3),改用 toBeCloseTo(0.3)(Jest)或自定义断言