double精度问题
不知道有没有小可爱在计算金额时写过类似如下的代码:
/**
* 计算金额
* **/
@Test
void calMoney() {
double da = 0.2d;
double db = 0.1d;
System.out.println(da + db);
// 答案是0.3还是0.30000000000000004呢?
}
上面的计算其实是不等于0.3 ,是不是满脑袋的问号,这不是小学的加法吗?因为计算机在计算double时可能会丢失精度。
究其原因是计算机其实无法用二进制精确的表示每个小数。大家都知道当今时代的计算机都是采用二进制来表示的,比如电信号0表示关,1表示开,计算规则都是逢二进一,比如十进制的10用二进制表示就等于1010,整数的二进制大家都很熟悉了。但是如果十进制的0.1用二进制如何来表示呢?小数用二进制的规则大家还记得吗?就是用小数乘以2取整数,如果大于1就减1后再乘2,直到小数是0
那么来计算下十进制0.1的二进制数呢
0.1*2=0.2 —>0
0.2*2=0.4—->0
0.4*2=0.8—->0
0.8*2=1.6—->1
0.6*2=1.2—->1
0.2*2=0.4—->0
0.4*2=0.8—->0
0.8*2=1.6—->1
0.6*2=1.2—->1
0.2*2=0.4—->0
看到这里小伙伴是不是就看到产生循环了,0.0 0011 0011 0011 0011 0011 ~
同理十进制的0.2用二进制来表示 0.0011001100110011~
那么两个数相加
0.00011001100110011~
0.00110011001100110~
0.0100110011001100110011001100110011001100110011001100110011001~1001
将上面这个无限小数转换为十进制就无限接近于0.3了,但不等于0.3。
如何避免浮点数精度问题
在一个伸手不见五指的夜晚,我掏出我的小霸王手机,抢了两个红包,恰好一个是0.1元,一个是0.2元,那我的账号余额会是0.30000000000000004元吗?怀着都科学敬畏的心打开了用六位密码保护的账户,看到是0.30元我心里舒畅多了,微信的小伙伴还是技术过了关的【田园犬头】

那为啥没有出现0.1元加0.2元不等于0.3元的情况呢?
在Java中可以通过BigDecimal即可解决问题
/**
* 计算金额
* **/
@Test
void calMoney() {
Double da = 0.1D;
Double db = 0.2D;
BigDecimal totalAmount = new BigDecimal(da.toString()).add(new BigDecimal(db.toString()));
System.out.println(totalAmount);
// 这样写就没有问题了,输出0.3
}
###