为什么 new BigDecimal("0.015").compareTo(new BigDecimal(0.015)) return -1?
Why does new BigDecimal("0.015").compareTo(new BigDecimal(0.015)) return -1?
为什么 new BigDecimal("0.015").compareTo(new BigDecimal(0.015))
return -1?
如果我希望这两者相等,是否有其他方法可以比较它们?
由于浮点运算的不精确性,它们并不完全相等
System.out.println(new BigDecimal(0.015));
显示
0.01499999999999999944488848768742172978818416595458984375
为了扩展@Reimeus 的
因此,例如,2⁻² 或 0.25 可以精确表示。 0.875是(2⁻¹ + 2⁻² + 2⁻³),所以也可以准确表示。只要能用幂次之和来表示这个数,其中上下次幂相差不超过53,那么这个数就可以精确表示。绝大多数数字不符合这种模式!
特别是0.15不是2的幂,也不是2的幂之和,所以表述不准确。
另一方面,字符串构造函数确实通过在内部使用不同的格式来存储数字来准确地存储它。因此,当您比较两者时,它们比较不同。
这里实际发生的是这样的:
0.015
是原始双精度数。也就是说,你一写,就已经不是0.015了,而是0.0149...
。 编译器将其存储为字节码中的二进制表示形式。BigDecimal
的构造是为了 准确地 存储提供给它的任何内容。在这种情况下,0.0149...
BigDecimal
也能够将字符串解析为 精确的 表示。在这种情况下"0.015"
被准确地解析为0.015
。尽管double
不能表示该数字,但BigDecimal
可以- 最后,当你比较它们时,你会发现它们并不相等。有道理。
每当使用 BigDecimal
时,请注意以前使用的类型。 String
、int
、long
将保持精确。 float
和 double
有通常的精度警告。
A double
不能准确表示值 0.015
。它可以用其 64 个二进制位表示的最接近的值是 0.01499999999999999944488848768742172978818416595458984375
。构造函数 new BigDecimal(double)
旨在保留 double
参数的精确值,它永远不会完全是 0.015
。因此,您的比较结果。
但是,如果您显示 double
值,例如:
System.out.println(0.01499999999999999944488848768742172978818416595458984375);
它输出 0.015
——这暗示了一个解决方法。 Converting a double
to a String
选择最短的十进制表示形式,以区别于其他可能的 double
值。
因此,如果您从 double
的 String
表示中创建一个 BigDecimal
,它将具有您预期的更多值。这个比较是正确的:
new BigDecimal(Double.toString(0.015)).equals(new BigDecimal("0.015"))
事实上,方法 BigDecimal.valueOf(double)
正是为此目的而存在的,因此您可以将上面的内容缩短为:
BigDecimal.valueOf(0.015).equals(new BigDecimal("0.015"))
仅当您的目的是保留参数的精确二进制值时,才应使用 new BigDecimal(double)
构造函数。否则,调用BigDecimal.valueOf(double)
,其文档说:
This is generally the preferred way to convert a
double
(orfloat
) into aBigDecimal
.
或,如果可以的话使用String
并完全避免double
的微妙之处。