【自种树自乘凉】0.1 + 0.2 == 0.3 ?

842 阅读2分钟

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战

答案是:

0.1 + 0.2 不等于 0.3!

谷歌浏览器运行结果为:

通过浏览器控制台可看到结果是令人奇怪的 0.30000000000000004 而不是 0.3

这是因为我们的计算机在存储数据的时候有一个基本的原则:

用有限的存储空间,来存储二进制数据。

上面这句话有两个关键点:

  1. 有限的存储空间
  2. 二进制数据

请记住它们。

下面继续:

也就是说,不管是 0.1 还是 0.2 我们的计算机都要先将它转化成二进制的 0.1 和 0.2

但是,十进制的 0.1 转化为二进制时,得到的是一个无限循环小数:0.00011…,十进制的 0.2 转化为二进制时亦是如此

这里得到一个关键点:二进制无法「用有限的位数」来表示 0.1 和 0.2

综上:

计算机用了一个有限的空间,存储了二进制的 0.1 和 0.2 (但是这样必定会损失精度)

所以,计算机存储的其实是 0.1 和 0.2 的近似值。

就是这样,两个近似值相加,结果极大概率也是 0.3 的近似值。

所有才有了 0.1 + 0.2 !== 0.3 的结果。

另外,这不是只有 JavaScript 才会出现问题,0.30000000000000004.com/ 这个网站就列举了各种语言 0.1 + 0.2 的结果...

不推荐用 JS 进行浮点运算

由于上面说到的,JS 精度丢失问题,所有并不推荐用 JS 进行浮点运算,特别是进行与“钱”相关的计算场景。

在进行浮点运算之前,我们也尽可能先判断两个浮点数之间的差值的绝对值有没有超出误差精度:

function fn(a, b) {
  return Math.abs(a - b) < Number.EPSILON
}
fn(0.1 + 0.2, 0.3)

引入十进制运算

TC39 Decimal proposal

JS 中默认的数字运算其实是隐式转二进制运算,所以现在有了这个十进制运算的提案,也就是说,在将来 0.1 + 0.2 !== 0.3 在 JS 中将不再存在。