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
このアサーションのように、equals()
メソッドを使用してBigDecimals
を比較することはできません。これは、この等しい関数がスケールを比較するためです。スケールが異なる場合、数学的に同じ数であっても、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()
と呼ばれるメソッドもあります。このメソッドは、負、0、および正の場合に-1、0、または1を返します。したがって、ゼロをテストすることもできます
_assertEquals(0, actual.signum());
_
コードには2つの問題があります。
new BigDecimal("22.3")
の代わりに文字列コンストラクター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
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をとるコンストラクターを使用して、以下の関連リンクを確認してください
関連項目