58

BigDecimalを使用して単純な乗算を実行していますが、ゼロを乗算すると奇妙な動作が見られます(このユースケースではゼロを乗算するのが正しいです)。

基本的な数学では、ゼロを掛けたものはすべてゼロに等しくなることがわかります(ゼロ積プロパティ乗算プロパティを参照) 。

ただし、次のコードは常に同じエラーで失敗します。

assertEquals(new BigDecimal(0), new BigDecimal(22.3).multiply(new BigDecimal(0)));
java.lang.AssertionError: 
Expected :0
Actual   :0E-48

これはBigDecimalの不正確さですか、それとも私がどこかに欠けている数学のニッチな分野がありますか?

注:IntelliJ11で実行されているJDK1.6.0_27

4

3 に答える 3

84

このアサーションのように、equals()メソッドを使用して比較することはできません。BigDecimalsこれは、この equals 関数がscaleを比較するためです。スケールが異なる場合、equals()数学的に同じ数であっても false を返します。

ただしcompareTo()、必要なことを行うために使用できます。

@assylias が指摘しているように、new BigDecimal("22.3")コンストラクターを使用して倍精度の問題を回避する必要もあります。

BigDecimal expected = BigDecimal.ZERO;
BigDecimal actual = new BigDecimal("22.3").multiply(BigDecimal.ZERO);
assertEquals(0, expected.compareTo(actual));

signum()負、ゼロ、正に対して -1、0、または 1 を返すというメソッドもあります。したがって、ゼロをテストすることもできます

assertEquals(0, actual.signum());
于 2012-08-14T09:24:35.130 に答える
47

コードには 2 つの問題があります。

  • 他の回答でアドバイスされているように、 BigDecimal を equals ではなく compareTo と比較する必要があります
  • ただし、倍精度の問題を回避するためnew BigDecimal("22.3")に double コンストラクターの代わりに文字列コンストラクターも使用する必要があります。new BigDecimal(22.3)

つまり、次のコード (compareTo を正しく使用している) は依然として false を返します。

BigDecimal bd = new BigDecimal(0.1).multiply(new BigDecimal(10));
System.out.println(bd.compareTo(BigDecimal.ONE) == 0);

なぜなら0.1d * 10d != 1

于 2012-08-14T09:28:15.943 に答える
20

equals()onは比較BigDecimalのために の内部状態をチェックしますBigDecimal

以下のコードを参照してください

public boolean equals(Object x) {
    if (!(x instanceof BigDecimal))
        return false;
    BigDecimal xDec = (BigDecimal) x;
    if (x == this)
        return true;
    if (scale != xDec.scale)
        return false;
    long s = this.intCompact;
    long xs = xDec.intCompact;
    if (s != INFLATED) {
        if (xs == INFLATED)
            xs = compactValFor(xDec.intVal);
        return xs == s;
    } else if (xs != INFLATED)
        return xs == compactValFor(this.intVal);

    return this.inflate().equals(xDec.inflate());
}

値を比較したい場合は、compareTo()

コードを次のように変更します

assertEquals(0 , new BigDecimal(0).compareTo(new BigDecimal(22.3).multiply(new BigDecimal(0)));

アップデート:

精度を高めるために、BigDecimal のパラメーターとして String を取るコンストラクターを使用します。以下の関連リンクを確認してください。


こちらもご覧ください

于 2012-08-14T09:25:50.030 に答える