资讯专栏INFORMATION COLUMN

从一个 bug 看 javascript 的精度丢失的问题

NusterCache / 1006人阅读

摘要:就像一些无理数不能有限表示,如圆周率,等。遵循规范,采用双精度存储,占用。参考中不会失去精度的最大值数字精度丢失的一些典型问题

问题描述

后端返回 { spaceObject: { objectId: "1049564069045993472" } }

前端模版,使用的是 atpl 模版

前端获取 objectId 的方式,const objectId = $("#test").data("id")

正常理解,我们获取到的 objectId 就是返回的 1049564069045993472,可是现实情况是这个 objectId1049564069045993500

问题拆分 一,为什么从 dom 中获取的字符串会变成数字

查看 zepto 代码可知,由于通过 $("#test").data("id") 获取到的字符串 "1049564069045993472" 经过 deserializeValue 方法之后就变成数字了。

关键代码如下:

data: function (name, value) {
      //[Opt:C]将原本在父级作用域的变量转移至局部变量
      var capitalRE = /([A-Z])/g,
        data = this.attr("data-" + name.replace(capitalRE, "-$1").toLowerCase(), value)
      return data !== null ? deserializeValue(data) : undefined
    },

// "true"  => true
  // "false" => false
  // "null"  => null
  // "42"    => 42
  // "42.5"  => 42.5
  // "08"    => "08"
  // JSON    => parse if valid
  // String  => self
function deserializeValue(value) {
    var num
    try {
      return value ?
        value == "true" ||
        ( value == "false" ? false :
          value == "null" ? null :
            !/^0/.test(value) && !isNaN(num = Number(value)) ? num :
              /^[[{]/.test(value) ? $.parseJSON(value) :
                value )
        : value
    } catch (e) {
      return value
    }
  }
二,为什么数字跟 dom 中获取的不一致

由于javascript的能够保持精度的最大值是 9007199254740991,所以由于上面那个数字大于这个最大安全数,所以会出现失去精度的问题。

引申 javascript 中精度丢失的几种情况 1. 简单的浮点数相加

0.1 + 0.2 !== 0.3 // true
0.1 + 0.2 === 0.3 // false
)

2. 大整数丢失精度

99999999999999999 === 100000000000000000

3. toFxied 有些情况下不会四舍五入

(12.235).toFixed(2) // 12.23

数字精度丢失问题原因分析

首先,javascript 中保持精度不丢失的数值是有个范围的,是在 Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER 之间. Number.MAX_SAFE_INTEGER => 9007199254740991 => 2的53次方-1

ECMA Section 8.5 - Numbers Note that all the positive and negative integers whose magnitude is no greater than 253 are representable in the Number type (indeed, the integer 0 has two representations, +0 and −0).

计算机的二进制实现和位数限制有些数无法有限表示。就像一些无理数不能有限表示,如 圆周率 3.1415926...,1.3333... 等。JS 遵循 IEEE 754 规范,采用双精度存储(double precision),占用 64 bit。如图

* 1位用来表示符号位
* 11位用来表示指数
* 52位表示尾数

深入了解

解决方案

使用 big.js库

如果是小数加减可以通过先将所有小数转化为整数(乘倍数),然后完成运算,最后缩小回去(除倍数)。

0.01 + 0.2 // 0.21000000000000002
(0.01 * 100 + 0.2 * 100) / 100 // 0.21

参考

javascript 中不会失去精度的最大值

JS数字精度丢失的一些典型问题

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/98303.html

相关文章

  • 数据精度问题自查手册

    摘要:前言在数据敏感的业务场景中,常常会碰到数据精度问题,尤其在金额显示占比统计等地方,该问题尤为显著。计算机原理真香数值的精度问题,其实是非常基础的计算机原理知识。前言 在数据敏感的业务场景中,常常会碰到数据精度问题,尤其在金额显示、占比统计等地方,该问题尤为显著。由于数据的每一位有效数字都包含真实的业务语义,一点点偏差甚至可能影响业务决策,这让问题的严重性上升了几个阶梯。 那,什么是精度丢失...

    liangzai_cool 评论0 收藏0
  • 由parseInt 引发问题---想到浮点运算精度丢失---透js number encod

    摘要:如题先陈述下问题背景偶尔测测自己写的计算器,随便输入玩嘛,然后发生下面诡异的事情当我从一个输入到十个的时候,过程显示都是正确的,像这样继续输入一个的时候,然后就这个样子了什么原因呢看了下自己的代码,代码重要部分长这样的这里用了一下强制转化为 如题 先陈述下问题背景 偶尔测测自己写的计算器,随便输入玩嘛,然后发生下面诡异的事情:当我从一个 1 输入到十个 1 的时候,过程显示都是正确的...

    hightopo 评论0 收藏0
  • 探寻 JavaScript 精度问题以及解决方案

    摘要:推导为何等于在中所有数值都以标准的双精度浮点数进行存储的。先来了解下标准下的双精度浮点数。精度位总共是,因为用科学计数法表示,所以首位固定的就没有占用空间。验证完成的最大安全数是如何来的根据双精度浮点数的构成,精度位数是。 阅读完本文可以了解到 0.1 + 0.2 为什么等于 0.30000000000000004 以及 JavaScript 中最大安全数是如何来的。 十进制小数转为二...

    YanceyOfficial 评论0 收藏0
  • JavaScript 基础知识 - 入门篇(一)

    摘要:如图意义位用来表示符号位位用来表示指数位表示尾数浮点数,比如无限循环无限循环此时只能模仿十进制进行四舍五入了,但是二进制只有和两个,于是变为舍入。这即是计算机中部分浮点数运算时出现误差,丢失精度的根本原因。 showImg(http://ww1.sinaimg.cn/large/9c47d583gy1fmtw1ma9g4j21hc0u0ach.jpg); 前言 最近一直有小伙伴跟我说J...

    sarva 评论0 收藏0
  • 「干货」细说 Javascript浮点数精度丢失问题(内附好课推荐)

    摘要:前言最近,朋友问了我这样一个问题在中的运算结果,为什么是这样的虽然我告诉他说,这是由于浮点数精度问题导致的。由于可以用阶码移动小数点,因此称为浮点数。它的实现遵循标准,使用位精度来表示浮点数。 showImg(https://segmentfault.com/img/remote/1460000018981071); 前言 最近,朋友 L 问了我这样一个问题:在 chrome 中的运算...

    senntyou 评论0 收藏0

发表评论

0条评论

NusterCache

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<