JavaScript中0.1+0.2为什么不等于0.3

我们都知道0.1 + 0.2 = 0.3,但是在JavaScript中0.10.2得到的不是0.3,而是 0.30000000000000004。由于这种微小的舍入错误,导致很难测试特定的浮点值。比如下面的例子:

let a = 0.1
let b = 0.2
if (a + b == 0.3) {  // false
  console.log("You got 0.3.")
}

这里检测两个数值之和是否等于0.3。如果两个数值分别是0.050.25,或者0.150.15,那没问题。但如果是0.10.2,如前所述,测试将失败。因此永远不要测试某个特定的浮点值。

let a = 0.05
let b = 0.25
if (a + b == 0.3) {
  console.log("You got 0.3.")  // You got 0.3.
}

之所以存在这种舍入错误,是因为使用了 IEEE 754 数值(64位),即52位小数、11位指数、1位符号,小数超过52位就会发生精度丢失,这种错误并非ECMAScript所独有。其他使用相同格式的语言也有这个问题。
在这里插入图片描述

符号位 (Sign): 决定数是正数(s=0)还是负数(s=1)。

指数位 (Exponent): 是 2 的幂(可能是负数),它的作用是对浮点数加权。

有效数字位 (Significand): 是二进制小数,它也被称为尾数位(Mantissa)、系数位(Coefficient)。

在这之前,我们先来了解一个小概念,当我们要标记或运算某个较大或较小且位数较多时会使用科学记数法,这样会少浪费很多空间和时间,例如:19971400000000=1.99714×10^13。

这里用0.125作为示范,转换为二进制,用的是乘二取整,只计算小数位,从上至下得到0.001

  • 0.125 x 2 = 0.25,整数部分是0
  • 0.25 x 2 = 0.5,整数部分是0
  • 0.5 x 2 = 1.0,整数部分是1

接下来,我们把0.1转换为二进制,对应是1.10011... × 2^-4

  • 0.1 x 2 = 0.2,整数部分是0
  • 0.2 x 2 = 0.4,整数部分是0
  • 0.4 x 2 = 0.8,整数部分是0
  • 0.8 x 2 = 1.6,整数部分是1
  • 0.6 x 2 = 1.2,整数部分是1
  • 0.2 × 2 = 0.4,整数部分是0

这里我们发现无法进行整除,循环0110,那么十进制的0.2也是会有同样的结果,因为我们可以从上面的结果里面看到从0.2开始进行乘2就一样会得到一个无限循环,循环的部分依旧是0110。那么肯定会出现后续的位置无法存储进去,这样就迫使计算机取一个近似的数字。

我们知道31/3相加可以得到3/3也就是1,不过这是十进制,就类似于我们把1除以3得到的0.333的无限循环以后再进行相加,很明显这些无限循环的0.333相加怎么也没有办法得到一个完整的1

解决方法: 因为小数乘二取整会有无限循环的情况,但是整数除二取余是不会的,所以整数部分不会出现精度丢失问题。

let a = 0.1
let b = 0.2
if ((a * 10 + b * 10) / 10 == 0.3) {
  console.log("You got 0.3.")  // You got 0.3.
}
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值