为什么0.1 + 0.2 != 0.3 ???

1、JavaScript计算的翻车现场

 

    所以,为什么会出现这样的结果呢?哪些计算又会出现这样的问题呢,让我们一步步的来分析一下~~~

2、JavaScript是如何表示数字的

  • 计算机遵循 IEEE 754 标准 ,是将信息转化为二进制进行存储的,JavaScript使用Number类型表示数字(整数和浮点数),而JS采用的是双精度版本,也就是通过64位来表示一个数字,具体如下:(1 + 11 + 52)

 

 

       注意:虽然只有52位来表示有效数字,但是JS的最大安全数字是JS_NUMBER_MAX_SAFE_INTEGER == Math.pow( 2,53)-  1 而不是Math.pow( 2,52)-  1(转成整数就是16位),这是因为二进制表示有效数字总是1.xx…xx的形式,尾数部分f在规约形式下第一位默认为1(省略不写,xx..xx为尾数部分f,最长52位)。因此,JavaScript提供的有效数字最长为53个二进制位(64位浮点的后52位+被省略的1位)

3、运算时发生了什么

    一、进制转换

  • 十进制整数转化为二进制整数(除2取余,自下而上,逆序排列)

  • 十进制小数转化为二进制小数(乘2取整,自上而下,顺序排列)

          由上面可知:173 -----> 10101101

                                0.8125 -----> 0.1101

                                173.8125 -----> 10101101.1101

  • 工具中直观的表示两者在计算机内存中的表现形式
    • 0.1 -----> 0 0011 0011 0011.....(无限循环)

    • 0.2 -----> 0011 0011 0011.....(无限循环)

2

  • 由此可以看出,0.1与0.2都是无限循环小数,JS的双精度版本会对这种小数的二进制进行取有效位数,从而造成精度丢失。
  • 由于JS的最大安全数字是16位,因此我们可以通过number.toPrecision(16)来进行精度运算,超过的部分会自动进行凑整处理。

二、对阶运算

  • 由于指数位数不相同,运算时需要进行对阶运算,因此也有可能造成精度丢失。

!!!结果:精度丢失可能出现在进制转化或者对阶运算中

3、以后如何解决

  • Number.prototype.toFixed(digits)精度为0-20之间,返回一个数值的字符串形式
  • Math.js
  • big.js
  • 等等

4、参考资料(哈哈哈,尊重作者,其实我就是写了一遍加深记忆~~~)

 

posted @ 2021-03-04 14:58  北栀女孩儿  阅读(257)  评论(0编辑  收藏  举报