资讯专栏INFORMATION COLUMN

js数值精度

孙吉亮 / 2155人阅读

摘要:大数值的精度问题能够被安全呈现的最大整数是,即。我们可以将需要比较的两个值进行相减,再与这个机器精度进行比较,如果在误差范围内,我们也视为两个值是相等的。

近期在项目中有出现大数值的订单号9148368244236619在调用接口时自动变成9148368244236620的情况,导致请求失误。本文特意总结了出现这种情况的原因,以及js精度相关的情况。

jquery[.data()]方法

在本次案例中,订单号是后端同步渲染到页面上的,

呈现在页面上的订单号数值没有问题9148368244236619 ,前端此时想获取到这个订单号:

var orderNumber = $(".j_OrderNumber).data("ordernumber"); // 9148368244236620

typeof(orderNumber) === "number" // true

在这个取值赋值的过程中,超过安全值的大数值发生了变化,从9148368244236619 变成了91483682442366120 ,这里的问题主要出现在jquerydata方法。

超过安全值Math.pow(2, 53)-1 -- 9007199254740991 的number类型在赋值的过程中会发生精度丢失,而我们在使用jquery的data方法取得的自定义html属性data-ordernumber值会强制转换成number类型,导致精度丢失。

而使用js原生的方法取dom节点的属性时,获取到的值都是string类型,这样就不会出现number类型精度丢失的问题。

var orderNumber = $(".j_OrderNumber")[0].dataset.ordernumber // "9148368244236619"

typeof(orderNumber) === "string" // true

所以我们在通过自定义属性取值number类型时,并且预期这些值会是类似订单号这种会超过安全阈值的数值时,不要使用jquery的data方法。

大数值的精度问题

能够被“安全”呈现的最大整数是Math.pow(2, 53) - 1,即9007199254740992 。在ES6中被定义为Number.MAX_SAFE_INTEGER

在开发环境,根据程序的特殊性,在有可能出现这种情况时我们应该杜绝掉超出安全阈值的大整数,并给出友好提示:

function isSafeInteger(num) {
    return typeof(num) === "number" && num % 1 == 0 && Math.abs(num) <= Math.pow(2, 53) -1;
}

在一般电商业务中比较常见出现大数值的场景也就是订单号了,这类场景后端传值给我们的时候都强制包装成string类型就会解决大多数的精度丢失问题了。

至于为什么会只有2的53次方-1的整数是安全的,可以看阮神的关于数值的文章有详细介绍

小数的精度问题

经典的 0.1 + 0.2 === 0.3 // false 问题

0.1 + 0.2 === 0.30000000000000004

小数比较

对于这类数值比较问题,如果我们已经知道了目标比较值,即如果我们已经明确要与0.3进行比较,我们也可以不需要得到0.1+0.2的真实期望结果值(0.3),因为如果我们要得到0.3,还需要对0.1和0.2进行操作。常规解法:

(0.1 * 10 + 0.2 * 10) / 10 = 0.3

在「你不知道的javascript」一书中有提到一种判断方法,设置一个误差范围值,通常也称为“机器精度”,对于javascript来说,这个值通常为Math.pow(2, -53)

我们可以将需要比较的两个值进行相减,再与这个机器精度进行比较,如果在误差范围内,我们也视为两个值是相等的。

function numbersCloseEnoughToEqual(num1, num2) {
    return Math.abs(num1 - num2) < Math.pow(2, -53);
}
小数展示

对于电商业务来讲,小数经过四则运算后可能会出现失去精度的问题,但是作为展示来说我们都会调用toFixed()进行小数后几位的约定,调用了这个方法后小数失去精度的问题也就迎刃而解了,不可能出现0.30000000000000004 这样的数值。

所以在业务中有需要进行小数四则运算并会展示在页面中,调用toFixed()方法!

但是toFixed()也有失去精度的时候!

1.335.toFixed(2)
// "1.33"

解决办法

function toFixed(num, s) {
    var times = Math.pow(10, s)
    var des = num * times + 0.5
    des = parseInt(des, 10) / times
    return des + ""
}
小数的四则运算

参考

本文来自二口南洋,有什么需要讨论的欢迎找我。

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

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

相关文章

  • 数据精度问题自查手册

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

    liangzai_cool 评论0 收藏0
  • 如何解决0.1 +0.2===0.30000000000000004类问题

    摘要:方法使用定点表示法来格式化一个数,会对结果进行四舍五入。该数值在必要时进行四舍五入,另外在必要时会用来填充小数部分,以便小数部分有指定的位数。如果数值大于,该方法会简单调用并返回一个指数记数法格式的字符串。在环境中,只能是之间,测试版本为。 showImg(https://segmentfault.com/img/remote/1460000011913134?w=768&h=521)...

    yuanzhanghu 评论0 收藏0
  • ES6精华:数值扩展

    摘要:基础极值采用标准的位双精度格式存储数值。如果数值的精度超过此限度,第位及后面的会被丢弃。数值的极值分为两种可表示的极值和可精确计算的极值浮点型不算。超过精度的数值可正确显示,但由其计算得出的结果可能不准确。整型数值安全区间。 ES6为数值增加了些常量和方法,使计算更为简便安全。本篇概括了这中的精华知识。 1 基础 1.1 极值 JS采用IEEE 754标准的64位双精度格式存储数值。 ...

    newtrek 评论0 收藏0
  • 关于js小数浮点数操作出现的精度问题的原因以及解决方法

    摘要:我们可以利用该函数限定返回数值的位数,从而达到提高精度的效果。 一、问题的引入 今天在看基础js文章的时候发现了一个浮点数的精度问题,当打印小数相加的时候有时候会出现数值不准确的情况,如果是在做一些需要数据精度要求较高的工作的时候稍有不慎就会出现问题 console.log(0.1+0.1) //0.2 console.log(0.1+0.2) //0.3000000000000000...

    Chiclaim 评论0 收藏0
  • JS. ES5重点笔记】数据类型

    摘要:是最特殊的类型,表示没有意义的数,例如。十六进制数八进制数十进制数十六进制数对于部分情况,和存在分歧。例如,表示希腊字符关于字符串的转换,其实核心就是函数,如果是数字型,还可以添加参数,使之变为二进制八进制十进制十六进制数。 虽然目前已经算是ES6的时代,然是ES5的尾巴仍在众多框架中出现,JS我虽然通过视频等方式学习,曾经做过项目,但是仍对部分细节和原理不了解,通过阅读这本书,希望能...

    Yu_Huang 评论0 收藏0

发表评论

0条评论

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