float精度丢失问题详解

今天运行一个程序,发现一个很有意思的情况,可以看到代码如下所示

public static void main(String[] args) {
        float a = 1;
        for (int i = 0; i<20000000; i++) {
            a++;
        }
        System.out.println(a);
}

public static void main(String[] args) {
        float a = 20000000;
        float b = a + 1;
        float c = b - a;
        System.out.println(b);
        System.out.println(c);
}

上面两段代码的输出结果是什么呢?输出结果如下:

1.6777216E7

2.0E7
0.0

好像和我们预期的不太一样,为什么会出现这种情况呢?那就要从我们的计算机底层说起,计算机内只有0,1来表示内容,对于整数我们知道可以转化为2进制去表示,那么对于小数,计算机内部是怎么表示的呢?在计算机内部有一个公式来表示小数;公式如下:

以32位计算机来说

其中:s-为符号位。占用一个bit位,表示是正数还是负数的作用。

           e-为指数位,占用8个bit位,也就是可以表示0~255个数字。

           f-为有效位,占用23个bit位,用来表示小数点后的有效位数。

以小数0.5为例,转化成上面的公式就表示如下:

为什么浮点数进行相加会出现精度丢失呢?

首先我们要知道浮点数进行相加需要遵守的原则就是先对齐,在计算,因为两个浮点数进行加法运算的时候,可能指数位是不一致的,所以需要先把指数位保持一致,然后再去计算有效位的加法就可以了。

以0.5 + 0.125为例:

数字s位大小e位大小f位
0.50-11.0...
0.1250-31.00...
0.125向0.5进行指数对齐后0-10.01....

所以计算结果为

所以在加法运算过程中,指数位较小的数,需要在有效位进行右移,在右移的过程中,最右侧的有效位就被丢弃掉了。这会导致对应的指数位较小的数,在加法发生之前,就丢失精度。其中有效位置有23位,当两个数的指数位相差23位后,对应的右移23位后,所有的有效位全部丢失,所以就会出现相面的计算情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值