奇怪的Double运算
今天测试同学反馈有一个运行了很久的程序,最近的崩溃率很高,通过日志查询发现,这是一个查询进度的接口,进度结果的精度是小数点后两位。
但是日志中却有很多的超过这个精度的结果,简化了一下代码:
1 double progress = 0.07000000000001D; 2 DecimalFormat df = new DecimalFormat("0.00"); 3 String value = df.format(progress); 4 if (progress > 0 && progress <= 1) { 5 double progressResult = Double.parseDouble(value); 6 progressResult = progressResult * 100; 7 }
这里首先是将progress的精度转换为小数点后两位,然后再进行乘以100 ,目的是为了转换成100%的结果,但是执行起来结果却和我们预期的不一样。
这里我们通过断点的方式可以看到,转换完之后的progressResult竟然又恢复到了原来的精度。
这是因为在计算机的内部是通过二进制码来进行计算的,我们看到的double的值可能是0.1,但是实际情况可能是0.100000000000000001,因为要展示这个数字是需要再从二进制数转回成十进制的,所以后面的内容就无法正确的显示。但是仍然是真是存在的。所以我们虽然前面已经通过Format的方式将progress的精度调整了,但是后面的位数还是存在的,所以在乘以100之后,结果就变成了现在的结果。所以在程序中,如果有double或者是float的值进行计算的,一定要使用BigDecimal来进行正确的处理。
下面是正确的处理方式:
1 double progress = 0.07000000000001D; 2 DecimalFormat df = new DecimalFormat("0.00"); 3 String value = df.format(progress); 4 if (progress > 0 && progress <= 1) { 5 BigDecimal valueResult = new BigDecimal(value); 6 double progressResult = valueResult.multiply(new BigDecimal(100)).doubleValue(); 7 }