JavaScript的数字运算中0.1+0.2!=0.3问题

2019-08-15  本文已影响0人  Kevin丶CK

前景

在正常的数学逻辑思维中,0.1+0.2=0.3这个逻辑是正确的,但是在JavaScript中0.1+0.2!==0.3,这是为什么呢?

分析

在计算机中,数字无论是定点数还是浮点数都是以多位二进制的方式进行存储的。在JS中数字采用的IEEE 754的双精度标准进行存储,无需关注他的存储形式,只需要简单的理解成就是存储一个数值所使用的二进制位数比较多而已,这样得到的数会更加精确。
由于采用二进制存储,而对于像0.1这样的数值无法整除,最后算下来会是 0.000110011....由于存储空间有限,最后计算机会舍弃后面的数值,所以只能得到一个近似值。在JS中采用的IEEE 754的双精度标准也是一样的道理,当出现这种无法整除的小数的时候就会取一个近似值,在js中如果这个近似值足够近似,那么js就会认为他就是那个值。
通过测试得到,在浏览器打印0.10000000000000010.10000000000000001

chrome Firefox
所以可以理解为,由于0.1转换成二进制时是无限循环的,所以在计算机中0.1只能存储成一个近似值。另外说一句,除了那些能表示成 x/2^n 的数可以被精确表示以外,其余小数都是以近似值得方式存在的。

结论

所以在0.1 + 0.2这个式子中,0.1和0.2都是近似表示的,在他们相加的时候,两个近似值进行了计算,导致最后得到的值是0.30000000000000004


chrome

方案解决

最好的方法是设置一个误差范围值,通常称为”机器精度“,而对于Javascript来说,这个值通常是2^-52,而在ES6中,Number提供了一个API:Number.EPSILON,而这个值正等于2^-52。这个值非常非常小,在底层计算机已经帮我们运算好,并且无限接近0,但不等于0,。这个时候我们只要判断(0.1+0.2)-0.3小于Number.EPSILON,在这个误差的范围内就可以判定0.1+0.2===0.3true

      function numbersEqual(a, b) {
        return Math.abs(a - b) < Number.EPSILON;
      }
      var a = 0.1 + 0.2,
        b = 0.3;
      console.log(numbersEqual(a, b));//true

考虑到兼容性可以这样处理

Number.EPSILON = Number.EPSILON || Math.pow(2,-52)
上一篇下一篇

猜你喜欢

热点阅读