前端金额js运算精度丢失问题及解决方案
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
本文转载于稀土掘金技术社区,作者:东方红杉 https://juejin.cn/post/7325627704782307337 前言前端开发中难免会遇到价格和金额计算的需求,这类需求所要计算的数值大多数情况下是要求精确到小数点后的多少位。但是因为JS语言本身的缺陷,在处理浮点数的运算时会出现一些奇怪的问题,导致计算不精确。 本文尝试从现象入手,分析造成这一问题原因,并总结和整合一些通用的解决方案,以供大家参考。 现象回顾下面的是JS进行数值运算过程中常见的问题,这个问题有个专业的名称叫精度丢失。 在 JavaScript 中整数和浮点数都属于 Number 数据类型,所有的数字都是以 64 位浮点数形式存储,整数也是如此。所以我们在打印 1.00 这样的浮点数的结果是 1 而非 1.00 。在一些特殊的数值表示中,例如金额,这样看上去有点别扭,但是至少值是正确了。然而要命的是,当浮点数做数学运算的时候,你经常会发现一些问题,举几个例子:
问题分析JavaScript 里的数字是采用 IEEE 754 标准的 64 位双精度浮点数。 该规范定义了浮点数的格式,对于 64 位的浮点数在内存中的表示,最高的 1 位是符号位,接着的 11 位是指数,剩下的 52 位为有效数字,具体对应如下:
符号位决定了一个数的正负,指数部分决定了数值的大小,小数部分决定了数值的精度。 IEEE 754 规定,有效数字第一位默认总是 1,不保存在 64 位浮点数之中。也就是说,有效数字总是 1.xx…xx 的形式,其中 xx..xx 的部分保存在 64 位浮点数之中,最长可能为 52 位。 因此,JavaScript 提供的有效数字最长为 53 个二进制位(64 位浮点的后 52 位 + 有效数字第一位的 1)。 那么,JavaScript 在计算 首先,十进制的
IEEE 754 标准的 64 位双精度浮点数的小数部分最多支持 53 位二进制位,所以两者相加之后得到的二进制就是下面的样子。
最终,因浮点数小数位的限制而截断的二进制数字,再转换为十进制,就成了 解决方案
这里是对网上常见的几个解决方案的汇总和整理,但是方案一和方案二都存在一定的局限性,我会在对应的方案里进行说明。通常我们前端做这类运算通常只用于表现层,所以这两个方案基本是够用的。 方案一在应对确定精度浮点数运算时,可以把金额转换成整数进行运算,最后再将结果转换成真实金额。
需要注意的是上面的例子只能处理最多两位小数的运算场景,如果小数位不确定这个方法是行不通的。 方案二JavaScript 内置的 toFixed() 方法可以将数字转换成保留指定小数位的字符串。这个方法适用于简单的金额计算。但需要注意舍入误差,因为转换后是字符串,失去了浮点数的特性,最后的结果坑你存在微小的误差。
第三方库现代前端发展至今,已经有很多成熟的类库来帮助我们解决此类问题,这类类库通常有很好的通用性和兼容性。 下面我将推荐几个人气较高的数字计算类库。 Math.jsMath.js 是专门为 JavaScript 和 Node.js 提供的一个广泛的数学库。它具有灵活的表达式解析器,支持符号计算,配有大量内置函数和常量,并提供集成解决方案来处理不同的数据类型像数字,大数字 (超出安全数的数字),复数,分数,单位和矩阵,功能强大,易于使用。 官网:mathjs.org[1] GitHub:GitHub - josdejong/mathjs: An extensive math library for JavaScript and Node.js[2] decimal.js为 JavaScript 提供十进制类型的任意精度数值。 官网:decimal.js API[3] GitHub:GitHub - MikeMcl/decimal.js: An arbitrary-precision Decimal type for JavaScript[4] big.jsBig.js 是一个用于处理任意精度的大数运算的 JavaScript 库。它解决了 JavaScript 中处理大数运算时精度丢失的问题,提供了更高精度的计算能力。 Big.js 库的特点包括:
Big.js 库非常适用于需要高精度计算的场景,如金融、密码学、科学计算和大数据处理等。它允许开发人员在 JavaScript 中进行准确的数字计算,避免了精度损失带来的问题。 官网:big.js API[5] GitHub:GitHub - MikeMcl/big.js: A small, fast JavaScript library for arbitrary-precision decimal arithmetic.[6] 总结本文对 Javascript 中浮点数运算出现的精度丢失问题进行了还原,分析了问题产生的原因在于二进制本身。同时给出了三个网络上比较成熟的解决方案,其中第一和第二方案基本可以满足大部分开发场景,如果不能满足就使用类库。 最后,建议所有对运算精度要求极高的业务场景都放到后端去运算,切记。 该文章在 2024/12/18 16:59:36 编辑过 |
关键字查询
相关文章
正在查询... |