您现在的位置是:亿华云 > IT科技类资讯
我是这样解决JavaScrip 加减乘除精度问题
亿华云2025-10-04 01:23:15【IT科技类资讯】0人已围观
简介前言众所周知的 JavaScript 二进制精度问题,浮点数的计算精度会存在缺失问题。最经典的例子就是为什么0.1+0.2 !== 0.3一句话概括就是:ECMAScript规范定义Number的类型
前言
众所周知的样解 JavaScript 二进制精度问题,浮点数的决J加减精度计算精度会存在缺失问题。最经典的乘除例子就是为什么0.1+0.2 !== 0.3
一句话概括就是:ECMAScript规范定义Number的类型遵循了IEEE754-2008中的64位浮点数规则定义的小数后的有效位数至多为52位导致计算出现精度丢失问题!
不过网上已经有很多专门的类库可以解决这个问题。
原生封装
加
/** ** 加法函数,问题用来得到精确的样解加法结果 ** 说明:javascript的加法结果会有误差,在两个浮点数相加的决J加减精度时候会比较明显。这个函数返回较为精确的乘除加法结果。 ** 调用:accAdd(arg1,问题arg2) ** 返回值:arg1加上arg2的精确结果 **/ function accAdd(arg1, arg2) { let r1, r2, m try { r1 = arg1.toString().split(.)[1].length } catch (e) { r1 = 0 } try { r2 = arg2.toString().split(.)[1].length } catch (e) { r2 = 0 } m = Math.pow(10, Math.max(r1, r2)) return (arg1 * m + arg2 * m) / m }减
/** ** 减法函数,用来得到精确的样解减法结果 ** 说明:javascript的减法结果会有误差,在两个浮点数相减的决J加减精度时候会比较明显。这个函数返回较为精确的乘除减法结果。 ** 调用:accSub(arg1,问题arg2) ** 返回值:arg1加上arg2的精确结果 **/ function accSub(arg1, arg2) { var r1, r2, m, n; try { r1 = arg1.toString().split(".")[1].length; } catch (e) { r1 = 0; } try { r2 = arg2.toString().split(".")[1].length; } catch (e) { r2 = 0; } m = Math.pow(10, Math.max(r1, r2)); //last modify by deeka //动态控制精度长度 n = r1 >= r2 ? r1 : r2; return ((arg1 * m - arg2 * m) / m).toFixed(n); }乘
/** ** 乘法函数,用来得到精确的样解乘法结果 ** 说明:javascript的亿华云乘法结果会有误差,在两个浮点数相乘的决J加减精度时候会比较明显。这个函数返回较为精确的乘除乘法结果。 ** 调用:accMul(arg1,arg2) ** 返回值:arg1乘以 arg2的精确结果 **/ function accMul(arg1, arg2) { let m = 0 let s1 = arg1.toString() let s2 = arg2.toString() try { m += s1.split(.)[1] ? s1.split(.)[1].length : } catch (e) { } try { m += s2.split(.)[1] ? s2.split(.)[1].length : } catch (e) { } return (Number(s1.replace(., )) * Number(s2.replace(., ))) / Math.pow(10, m) }除
/** ** 除法函数,用来得到精确的除法结果 ** 说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。 ** 调用:accDiv(arg1,arg2) ** 返回值:arg1除以arg2的精确结果 **/ function accDiv(arg1, arg2) { let t1 = 0 let t2 = 0 let r1 let r2 try { t1 = arg1.toString().split(.)[1].length } catch (e) { } try { t2 = arg2.toString().split(.)[1].length } catch (e) { } r1 = Number(arg1.toString().replace(., )) r2 = Number(arg2.toString().replace(., )) return (r1 / r2) * Math.pow(10, t2 - t1) }封装
定义一个函数来调用加减乘除方法,这样做有个好处,用到地方调用加减乘除方法一致,假设某个方法后面发现那个库更好用或者某个平台不兼容、算法不太严谨、扩展新的功能等等,我们只要维护这个函数就行,不用在考虑项目中某个组件单独引用,没有按照这个规范因为这次维护引发的新问题。
export const calcFn = { add() { const arg = Array.from(arguments) return arg.reduce((total, num) => { return accAdd(total, num) }) }, sub() { const arg = Array.from(arguments) return arg.reduce((total, num) => { return accSub(total, num) }) }, mul() { const arg = Array.from(arguments) return arg.reduce((total, num) => { return accMul(total, num) }) }, divide() { const arg = Array.from(arguments) return arg.reduce((total, num) => { return accDiv(total, num) }) } }big.js
介绍:任意精度十进制算术的小型、快速、易于使用的库。 特性:目前同类型最小包、无依赖、高防服务器包大小3 KB、兼容ECMAScript 3+可以说适用于所有浏览器。 官网:GitHubhttps://github.com/MikeMcl/big.js/
安装使用
浏览器
<script src=https://cdn.jsdelivr.net/npm/big.js@6.1.1/big.min.js></script>Node.js
npm install big.js使用
x = new Big(0.1) y = new Big(0.2) z = new Big(0.3) x.plus(y).eq(z) // true运算符操作函数
以下big.js目前支持运算符操作函数。
abs,取绝对值。 cmp,compare的缩写,即比较函数。 div,除法。 eq,equal的缩写,即相等比较。 gt,大于。 gte,小于等于,e表示equal。 lt,小于。 lte,小于等于,e表示equal。 minus,减法。 mod,取余。 plus,加法。 pow,次方。云服务器提供商 prec,按精度舍入,参数表示整体位数。 round,按精度舍入,参数表示小数点后位数。 sqrt,开方。 times,乘法。 toExponential,转化为科学计数法,参数代表精度位数。 toFied,补全位数,参数代表小数点后位数。 toJSON和toString,转化为字符串。 toPrecision,按指定有效位数展示,参数为有效位数。 toNumber,转化为JavaScript中number类型。 valueOf,包含负号(如果为负数或者-0)的字符串。封装
import Big from big.js export const calcFn = { add() { const arg = Array.from(arguments) return arg.reduce((total, num) => { return new Big(total).plus(new Big(num)) }).toString() * 1 }, sub() { const arg = Array.from(arguments) return arg.reduce((total, num) => { return new Big(total).minus(new Big(num)) }).toString() * 1 }, mul() { const arg = Array.from(arguments) return arg.reduce((total, num) => { return new Big(total).times(new Big(num)) }).toString() * 1 }, divide() { const arg = Array.from(arguments) return arg.reduce((total, num) => { return new Big(total).div(new Big(num)) }).toString() * 1 } }使用
calcFn.add(0.1, 0.2) !== 0.3 // falsebignumber.js
介绍:用于任意精度十进制和非十进制算术的 JavaScript 库。 特性:无依赖、包大小8 KB、兼容ECMAScript 3+可以说适用于所有浏览器。 官网:GitHubhttps://github.com/MikeMcl/bignumber.js
使用方法类似,同上。
decimal.js
介绍:为 JavaScript 提供十进制类型的任意精度数值。 特性:无依赖、包大小12.6 KB、兼容ECMAScript 3+可以说适用于所有浏览器。 官网:GitHubhttps://github.com/MikeMcl/decimal.js
使用方法类似,同上。
Math.js
介绍:用 Javascript 编写的简单数学库,可能不维护了。 特性:是一个广泛的 JavaScript 和 Node.js 数学库。它具有灵活的表达式解析器,支持符号计算,带有大量内置函数和常量,并提供了一个集成的解决方案来处理不同的数据类型,如数字、大数、复数、分数、单位和矩阵。功能强大且易于使用。 官网:GitHub总结
big.js适用于大部分十进制算术应用程序,因为不接受NaN或Infinity作为合法值。而且不支持其他基数的值。如果项目中没有非十进制算术这非常适合用,而且关键是包足过小,哈哈自己造的轮子后面还是觉得库比较香哈。
bignumber.js可能更适合金融应用,因为除非使用涉及除法的运算,否则用户无需担心会丢失精度。
decimal.js可能更适合更科学的应用程序,因为它可以更有效地处理非常小的或大的值。例如,它没有bignumber.js的限制,当将一个小指数的值与一个大指数的值相加时,bignumber.js会尝试执行全精度运算,这可能会导致操作不可行。
如上所述,decimal.js还支持非整数幂,并增加了三角函数和exp,ln和log方法。这些添加使decimal.js明显大于bignumber.js。
很赞哦!(4633)
相关文章
- ④注册门槛低
- 域名的选择方向有哪些?如何打造好的域名?
- .net.cn是什么域名?.net.cn在域名圈咋样?
- 如何选择适合自己的域名?怎么选择域名?
- 在数以亿计的网站中,我们应该抓住每一个可能带来宣传的机会,域名可以带有企业的名字,一般可以使用汉语拼音或者英语单词或者是相关缩写的形式,只要用户记住了你企业的名字,就能很容易的打出你的网站域名,同样的,记住了网站域名也能很快的记住你公司的名字。
- 域名有怎样的历程?从什么时候开始到结束?
- 京东APP百亿级商品与车关系数据检索实践
- 如何查询域名的价值?有什么方法?
- 众所周知,com域名拥有最大的流通市场和流通历史。最好选择com域名,特别是在购买域名时处理域名。其次可以是cn域名、net域名、org域名等主流域名,现在比较流行的王域名和顶级域名,都是值得注册和投资的。
- 基于Sentinel自研组件的系统限流、降级、负载保护最佳实践探索