浮点数陷阱—无法精确保存0.1 ?


陷阱:浮点数遵循IEEE754标准,无法精确保存0.1


问题

  • 看三行简单却诡异的代码,观察运行结果
       	double x = 1.0 / 10;
        double y = 1 - 0.9;
        double z = 0.1+0.2;
        
        // 观察x、y、z的结果
        
        System.out.println(x);
        System.out.println(y);
        System.out.println(z);

在这里插入图片描述

  • 为什么1 - 0.9 != 0.1 ?
  • 为什么0.1+0.2 != 0.3 ?

结论

  在计算机中,浮点数虽然表示的范围大,但是浮点数有个非常重要的特点——浮点数常常无法精确表示。

  例如,浮点数0.1在计算机中就无法精确表示,所以运算结果就会出现偏差。


解析

  如果你了解浮点数二进制存储机制,那么就很简单,二进制只能精确存储小数域是2的负指数幂及其线性组合的数。例如0.25、0.5…

  如果你不了解,那么一起来看…

    0.1 = 1/24 + 1/25 + 1/28 +1/29+1/212+1/213

    0.110=0.0001100110011001100110011…2

  这是一个二进制无限循环小数。

计算机内存有限,我们不能储存所有的小数位数,所以在某个精度点直接舍弃,单精度精确到23位,双精度精确到52位。

  也就是说,0.1在计算机内部根本就不是精确的0.1,而是一个有舍入误差的0.1。当代码被编译或解释后,0.1已经被四舍五入成一个与之很接近的计算机内部数字,导致计算还没开始,一个很小的舍入错误就已经产生了。这也就是上面问题产生的根本原因。

关于浮点数的存储机制请移步——浮点数揭秘——IEEE754


结语

  不同行业,要求的精度不是线性的,我们允许(对结果无关紧要的)误差存在,例如10.0001与10.001在铁路工程师看来都是合格的。
  虽然允许误差存在,但是程序员在使用浮点数进行计算或逻辑处理时,稍不注意,就可能会问题。
  记住,最好完全避免使用浮点数进行比较!

  在银行业务中用Java中的BigDecimal数学工具类来表示钱数。


水平有限,如有错误之处,还请指正。
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值