web-dev-qa-db-ja.com

BigDecimal( "5.50")がBigDecimal( "5.5")と等しくない理由と、この問題を回避する方法

実際、可能な解決策を見つけました

_//returns true
new BigDecimal("5.50").doubleValue() == new BigDecimal("5.5").doubleValue()
_

もちろん、Math.abs (v1 - v2) < EPSのようなもので比較をより堅牢にするために改善できますが、問題はこの手法が受け入れられるか、より良い解決策があるかということです。

Javaデザイナーがその方法でBigDecimalのequalsを実装することを決めた理由を誰かが知っていれば、読むのは面白いでしょう。

48
Roman

BigDecimalのjavadocから

等しい

public boolean equals(Object x)

このBigDecimalと指定されたObjectが等しいかどうかを比較します。 compareTo とは異なり、このメソッドは2つのBigDecimalオブジェクトが等しいと見なします(値とスケールが等しい場合のみ)(したがって、2.0はそうではありません)この方法で比較すると2.00に等しい)

単にcompareTo() == 0を使用してください

85
Colin Hebert

_==_を使用してdoubleを比較する 悪い考えのようです 一般的に。

比較する数値で同じものにsetScaleを呼び出すことができます。

_new BigDecimal ("5.50").setScale(2).equals(new BigDecimal("5.5").setScale (2))
_

スケールを2つのうち大きい方に設定する場所:

_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" );
_

ただし、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;
_

そしてもちろん、compareToは既に実装されているので、はるかに使いやすいです。

9
Nathan Hughes

先行ゼロを無視して比較する最も簡単な式は、Java 1.5:

bd1.stripTrailingZeros().equals(bd2.stripTrailingZeros())
4
user1708042