编辑:这个问题涵盖两个主题:
- 使用 in double 代替 float 的效率
- 舍入后的浮点精度
有什么理由不应该总是使用 Java 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)
知道为什么这个测试会失败,为什么我不应该总是使用 double 而不是 float 吗?当然,除了双精度外,还有一个比浮点数更宽的原因。
编辑:有趣的是 Assert.assertNotEquals(double,double,delta) 在这两种情况下都需要双精度,因此失败测试中返回的浮点数无论如何都会扩大为双精度,那么为什么测试失败呢?
编辑:可能这个其他问题是相关的,但不确定: 十六进制不一样
编辑:从这个问题的答案十六进制不一样可以得出结论,对于浮点数的 .99 的科学表示 IEEE 754 与相同值的双精度表示不同。这是由于四舍五入。
因此我们得到这个:
- 0.99 - 0.97 = 0.01999998 //在浮点情况下
- 0.99 - 0.97 = 0.020000000000000018 //在双重情况下
由于上述单元测试中的最大增量为 0.02 并且 0.01999998(在失败的测试中)低于 delta 值,这意味着这些数字看起来是相同的,但测试断言它们没有因此失败。
伙计们,你同意这一切吗?