JS | 0.1 + 0.2 === 0.3 吗

90 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第19天,点击查看活动详情

在 JS 中,和数字相关的类型由 Number 类型来进行表示,在这里数字可以是整数或浮点数。

那么 0.1 + 0.2 === 0.3 这个等式是否成立呢,先来运行如下代码来测试一下:

console.log(0.1 + 0.2)
console.log(0.1 + 0.2 === 0.3)
console.log(typeof (0.1 + 0.2))
console.log(typeof 0.3)

运行结果:

image.png

可以看到 0.1 + 0.2 在 JS 中的结算结果是 0.30000000000000004,其实会产生这样的结果是因为精度丢失。在两数相加时,数字会先转换成二进制,0.1 和 0.2 转换成二进制的时候尾数会无限循环,再进行对阶运算,JS 引擎对二进制进行截断后导致精度丢失。

了解这里面内在的原理,还是要从进制这里说起:

javascript 中数字类型采用的是 IEEE754 的双精度标准进行存储,可以存储的二进制精度为 64 位(小数还是整数都是 64 位),这64位包括3部分:符号位,指数位,有效位。

十进制和二进制的转换

十进制转换成二进制:

将十进制数除以 2,一直相除直到得到的商为 0,按照从低位到高位的顺序的一串由 0 和 1 组成的就是最终的二进制串。

  • 0.1:0.000110011001100110011001100110011001100110011001100110011001
  • 0.2:0.001100110011001100110011001100110011001100110011001100110011

二进制转换为十进制:

从二进制的低位开始,将每一位乘以2的幂数(从个位到前面的高阶位,从0开始依次累计1),小数部分与整数部分分别相加

如何使 0.1 + 0.2 == 0.3 成立?

ES6中提供了一种设置最小精度的方法 Number.EPSILON,比如:Number.EPSILON,等于 2 的-52 次方,误差如果小于这个值,就忽略不计。

function isEqual(a,b){
    return Math.abs(a-b)<Number.EPSILON;
}
Number.EPSILON = Math.pow(2,-52)
console.log(isEqual(0.1 + 0.2, 0.3))

运行结果最终为 true