編集:この質問は2つのトピックをカバーしています:
- フロートの代わりにダブルで使用する効率
- 丸め後の浮動小数点精度
float の代わりに常に Java double を使用すべきではない理由はありますか?
この質問をするのは、float を使用する場合のこのテスト コードが失敗し、唯一の違いは double ではなく float を使用することであるため、その理由が明確でないためです。
public class BigDecimalTest {
@Test public void testDeltaUsingDouble() { //test passes
BigDecimal left = new BigDecimal("0.99").setScale(2,BigDecimal.ROUND_DOWN);
BigDecimal right = new BigDecimal("0.979").setScale(2,BigDecimal.ROUND_DOWN);
Assert.assertEquals(left.doubleValue(), right.doubleValue(), 0.09);
Assert.assertEquals(left.doubleValue(), right.doubleValue(), 0.03);
Assert.assertNotEquals(left.doubleValue(), right.doubleValue(), 0.02);
Assert.assertNotEquals(left.doubleValue(), right.doubleValue(), 0.01);
Assert.assertNotEquals(left.doubleValue(), right.doubleValue(), 0.0);
}
@Test public void testDeltaUsingFloat() { //test fails on 'failing assert'
BigDecimal left = new BigDecimal("0.99").setScale(2,BigDecimal.ROUND_DOWN);
BigDecimal right = new BigDecimal("0.979").setScale(2,BigDecimal.ROUND_DOWN);
Assert.assertEquals(left.floatValue(), right.floatValue(), 0.09);
Assert.assertEquals(left.floatValue(), right.floatValue(), 0.03);
/* failing assert */ Assert.assertNotEquals(left.floatValue() + " - " + right.floatValue() + " = " + (left.floatValue() - right.floatValue()),left.floatValue(), right.floatValue(), 0.02);
Assert.assertNotEquals(left.floatValue(), right.floatValue(), 0.01);
Assert.assertNotEquals(left.floatValue(), right.floatValue(), 0.0);
}}
失敗メッセージ:
java.lang.AssertionError: 0.99 - 0.97 = 0.01999998. Actual: 0.9900000095367432
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failEquals(Assert.java:185)
at org.junit.Assert.assertNotEquals(Assert.java:230)
at com.icode.common.BigDecimalTest.testDeltaUsingFloat(BigDecimalTest.java:34)
このテストが失敗する理由と、float の代わりに常に double を使用するべきではない理由について何か考えはありますか? もちろん、ダブル以外の理由は、フロートよりも広いです。
編集: 面白いことに、Assert.assertNotEquals(double,double,delta) はどちらの場合も double を取るため、失敗したテストで返された浮動小数点数はとにかく double として拡張されているので、なぜテストが失敗するのでしょうか?
編集:この他の質問が関連している可能性がありますが、よく わかりません:16進数は同じではありません
編集: この質問hex not the sameへの回答から、float の .99 に対する IEEE 754 の科学的表現は、同じ値の double とは異なると結論付けることができます。これは丸めによるものです。
したがって、次のようになります。
- 0.99 - 0.97 = 0.01999998 //フロートの場合
- 0.99 - 0.97 = 0.020000000000000018 //二重の場合
上記の単体テストの最大デルタは 0.02 であり、(失敗したテストでは) 0.01999998 はデルタ値を下回っているため、数値は同じように見えますが、テストはそれらが失敗していないと主張していることを意味します。
みんな、これに同意しますか?