自由书

V1

2022/04/02阅读:17主题:默认主题

什么?在Java中0.1+0.2不等于0.3?浮点数精度丢失

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?
0.1+0.2=0.3?

那为啥没有出现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
    }

分类:

后端

标签:

Java

作者介绍

自由书
V1