最近遇到一个计算总金额的需求,我的做法是把double类型的金额相加,以为任务完成了,就提交代码了。代码合并的时候被告知这么写是错的,因此我研究了一下。
以float为例,先来看下面这段代码,并猜测一下结果
float c = 1.0f;
float b = 0.9f;
System.out.println(c - b);
System.out.println(c + b);
我们知道,数值在计算机中是以二进制的形式存储的,数值的计算先转成二进制,得出结果后再转成十进制。float第1位是符号位,2-9位是指数位,剩下23位是尾数位,这里取后24位,那么1.0
的存储就是:10000 0000 0000 0000 0000 0000
,0.9
存储的是0111 0011 0011 0011 0011 0011
,因此1-0.9和1+0.9的过程分别是
10000 0000 0000 0000 0000 0000
- 0111 0011 0011 0011 0011 0011
______________________________
= 0000 1100 1100 1100 1100 1101
10000 0000 0000 0000 0000 0000
+ 0111 0011 0011 0011 0011 0011
______________________________
= 1111 0011 0011 0011 0011 0011
使用Math.pow方法在编译器中计算结果,并与原来的值相比较:
0.100000024
1.9
0.10000002384185791
1.8999999761581421
分析:尾数部分最大是1-2的负23次方,2的23次方是8 388 608,因此float精度是在7-8位左右,超出部分四舍五入,这里以9位为例,那么相减取的9位为0.100000024,相加取得九位为1.900000000,当小数位为0时,会舍弃除第一个小数位之外的0,所得到的结果即为1.9