为什么 0.1+0.2 不等于 0.3 ; 14.2+80.9 不等于 95.1 ?

START

  • 番茄又来写点啥了。
  • 最近遇到一个很有趣的bug,在这里记录一下。

业务场景

  • 有两个金额A,B,我都做了保留两位小数的处理
  • 还有一个金额C,等于金额A的金额B的
  • 突然测试给我讲,番茄,你这金额C没有保留两位小数哦。
  • 查看了相关的bug,得出来的金额C展示的是95.10000000000001

到这里我第一反应,确实金额C没有做保留两位小数的处理

但是在我排查代码逻辑的时候,突然想到,明明金额A和金额B我都做了保留两位小数的处理呀。

随即,在浏览器中打印了一下,发现了一个有趣的事情。

14.2+80.9 = 95.10000000000001

在这里插入图片描述

问题分析

看到浏览器这里打印,14.2+80.9 = 95.10000000000001 。我就想到我们熟知的0.1+0.2 = 0.30000000000000004

JS红宝书相关说明呢:

  • 浮点数值的精度最高是17位小数,但是在算数计算式其进度远不如整数。

  • 关于浮点数值计算会产生误差的问题,有一点需要明确。这是基于IEEE754数值的浮点计算的通病。

    JS;JAVA;PYTHON 都会出现:0.1+0.2 = 0.30000000000000004

根本原因是什么呢:

首先,我们要知道,计算机存储数据呢,是以二进制0/1存储的,所以我们把0.10.2(十进制的)转换为二进制的:

0.1 => 0.0001 1001 1001 1001…(1001无限循环)
0.2 => 0.0011 0011 0011 0011…(0011无限循环)

但是我们计算机的硬件存储的位数是有限制的不可能无限循环下去,一般双精度浮点数总共占用64位,其中最多53位为有效精度数字(包括符号位),所以存储时只能存储:

0.1=>0.0001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001
0.2=>0.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011

所以

0.1+0.2=>

0.0100 1100 1100 1100 1100 1100 11001 100 1100 1100 1100 1100 1100

转换为十进制就是:0.30000000000000004

解决方案

遇到这种情况怎么处理呢。

  1. Math.round() 方法四舍五入或者toFixed() 方法保留指定的位数(对精度要求不高,可用这种方法)

  2. 将小数转为整数再做计算。

    2.1 这里可以配合Math.pow(10, n)放大10的n次方;

    2.2 小数点的位数可以这样获取:

    // num 我们需要计算的数字
    // l 小数点的位数
      try {
        l = num.toString().split('.')[1].length
      } catch (e) {
        l = 0
      }
    

END

  • 问题还是小问题,但是依旧很有意思,老生常谈。
  • 记录当下,ღ( ´・ᴗ・` )
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lazy_tomato

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值