为什么BigDecimal("5.50")不等于BigDecimal("5.5")以及如何解决这个问题?

Rom*_*man 49 java equals bigdecimal

实际上,我找到了可能的解决方案

//returns true
new BigDecimal("5.50").doubleValue() == new BigDecimal("5.5").doubleValue()
Run Code Online (Sandbox Code Playgroud)

当然,它可以通过类似的Math.abs (v1 - v2) < EPS方式进行改进,使比较更加健壮,但问题是这种技术是否可以接受或是否有更好的解决方案?

如果有人知道为什么java设计师决定以这种方式实现BigDecimal的平等,那么阅读它会很有趣.

Col*_*ert 86

来自BigDecimal的javadoc

等于

public boolean equals(Object x)

将其BigDecimal与指定Object的相等性进行比较.与compareTo此不同,此方法只考虑两个BigDecimal对象的值和比例相等(因此,当通过此方法进行比较时,2.0不等于2.00).

简单地使用 compareTo() == 0

  • 你不需要放弃对称来实现`equals`作为数值比较,所以对称性不是原因.我在这里明确地问了"为什么"问题:[为什么指定BigDecimal.equals来单独比较值和比例?](http://stackoverflow.com/questions/14102083/why-is-bigdecimal-equals-specified -to-比较,两者价值和规模,单独) (6认同)
  • @supercat我认为你不应该期望那些返回相同的值; `toString`没有要求它与`equals`一致.考虑`java.util.Set`实现 - 它们有一个严格指定的`equals`契约,但是一个`toString`,可以按任何顺序返回项目. (3认同)

use*_*042 10

从 Java 1.5 开始,最简单的比较忽略尾随零的表达式是:

bd1.stripTrailingZeros().equals(bd2.stripTrailingZeros())
Run Code Online (Sandbox Code Playgroud)


Nat*_*hes 9

使用==比较双打似乎是一个坏主意一般.

你可以在你要比较的数字上调用setScale:

new BigDecimal ("5.50").setScale(2).equals(new BigDecimal("5.5").setScale (2))
Run Code Online (Sandbox Code Playgroud)

你将把比例设置为两者中的较大者:

BigDecimal a1 = new BigDecimal("5.051");
BigDecimal b1 = new BigDecimal("5.05");
// wow, this is awkward in Java
int maxScale = Collections.max(new ArrayList() {{ a1.scale(), b1.scale()}});
System.out.println(
  a1.setScale(maxScale).equals(b1.setScale(maxScale)) 
  ? "are equal" 
  : "are different" );
Run Code Online (Sandbox Code Playgroud)

但是,使用compareTo() == 0是最好的答案.上述方法中其中一个数字的比例增加可能是compareMagnitude方法文档提到的"不必要的通货膨胀",当它说:

/**
 * Version of compareTo that ignores sign.
 */
private int compareMagnitude(BigDecimal val) {
    // Match scales, avoid unnecessary inflation
    long ys = val.intCompact;
    long xs = this.intCompact;
Run Code Online (Sandbox Code Playgroud)

当然,compareTo它已经很容易使用,因为它已经为您实现了.

  • 只有这样做才能考虑"5.051"=="5.05",因为setScale(2)将丢弃该额外数字,其中.compareTo(其他)将比较值而不考虑比例 (6认同)
  • Gareth,没有舍入模式参数的`setScale`不会丢弃额外的数字,而是会抛出ArithmeticException.所以这只有在额外数字全为零时才有效. (3认同)