Java 浮点运算精度:规避 equals 比较

作者:袖梨 2026-06-18
<p>Java中浮点数不能用equals()比较,因其按对象语义严格比较值与精度(标度),类型不同或标度不等均返回false;基本类型避免==,因二进制近似导致误差累积;应采用误差阈值法如Math.abs(a - b) < THRESHOLD。</p>

Java 中浮点数不能用 equals() 比较,根本原因在于它不是数值相等判断,而是对象语义的严格比较——既看值,也看精度(即小数位数)。哪怕数学上相等,只要标度不同,equals() 就返回 false

为什么包装类的 equals() 不可靠

Float 和 Double 的 equals() 方法内部会先检查类型,再比对数值和标度。例如:

  • new Float(0.1f).equals(new Double(0.1))false(类型不同)
  • new Double(1.0).equals(new Double(1.00))true(Double 标度不参与 equals 判断,但这是特例)
  • new BigDecimal("1.0").equals(new BigDecimal("1.00"))false(标度 1 ≠ 标度 2)

浮点基本类型别用 ==

float/double 是二进制近似表示,0.1 在内存中本就无法精确存储。运算后误差累积,直接 == 极易失败:

  • 0.1f + 0.2f == 0.3ffalse
  • 1.0 / 10 == 0.1dfalse(float 升级为 double 后,二进制近似值已不同)

正确比较方式:按场景选方法

普通精度容忍场景:用误差阈值

立即学习“Java免费学习笔记(深入)”;

  • 定义一个合理 THRESHOLD,比如 1e-6(float)或 1e-10(double)
  • 写成 Math.abs(a - b)

金融/高精度场景:用 BigDecimal

  • 构造必须用字符串:new BigDecimal("0.1"),禁用 new BigDecimal(0.1)
  • 比较统一用 compareTo()a.compareTo(b) == 0(只比数值,忽略标度)
  • 运算全程用 addsubtractmultiplydivide(除法务必指定 scale 和 RoundingMode)

BigDecimal 的 equals() 陷阱

equals()BigDecimal 中是“值 + 标度”双重校验。这意味着:

  • new BigDecimal("1.0").equals(new BigDecimal("1.00"))false
  • new BigDecimal("1.0").compareTo(new BigDecimal("1.00")) == 0true
  • someBigDecimal.equals("1.0") 总是 false(类型不匹配,不解析字符串)

相关文章

精彩推荐