js 加减乘除精度问题2

张开发
2026/4/11 4:37:09 15 分钟阅读

分享文章

js 加减乘除精度问题2
当我们使用bignumber, mathjs, Decimal 等处理 数字加减乘除的时候 会遇到 即使使用了,还是有精度问题例如const a new Decimal(val1);const b new Decimal(val2);const sum a.plus(b);结果不是我们期望的? why因为Decimal 要求参数是字符串, 当然他能够接受一直数值类型的. 但有没有想过这个数值本身精度就有问题呢例如 后端接口传过来的一个变量是个数字val1, 我们要求这个数字加上 0.1const a new Decimal(val1);const b new Decimal(‘0.1’);const sum a.plus(b);当js处理时 这个数字精度就有问题了解决方法最佳推动后端改为返回字符串 { “amount”: “123.45” }次选如果数值在安全范围内如两位小数的金额可尝试在这里插入代码片// 仅适用于固定小数位如货币constsafeStr(backendNumber).toFixed(2);// 先转为精确字符串constdnewDecimal(safeStr);toFixed 和 toPrecision 区别特性.toFixed(n).toPrecision(n)控制什么小数点后的位数固定小数位整个数字的有效数字位数返回类型字符串字符串是否四舍五入是是可能用科学计数法否始终定点表示是当数字太大或太小时典型用途货币显示如保留2位小数高精度数值的紧凑表示// decimalUtils.jsimport{Decimal}fromdecimal.js;// 默认配置constDEFAULT_CONFIG{precision:64,// 全局有效数字精度defaultDecimals:2,// 默认显示小数位数numberPrecision:15// 处理 number 时的有效数字位数};// 设置全局精度Decimal.set({precision:DEFAULT_CONFIG.precision});/** * 安全创建 Decimal 实例内部使用 */function_createDecimal(value,options){constconfigObject.assign({},DEFAULT_CONFIG,options);if(valuenull)returnnewDecimal(0);if(valueinstanceofDecimal)returnvalue;if(typeofvaluestring){constcleanStrvalue.trim();if(cleanStr)returnnewDecimal(0);returnnewDecimal(cleanStr);}if(typeofvaluenumber){if(!isFinite(value)){thrownewError(Invalid number:${value});}// 优先使用 fixedDecimals 修复适用于金额等已知小数位场景if(config.fixedDecimals!null){constfactorMath.pow(10,config.fixedDecimals);constroundedMath.round(value*factorNumber.EPSILON);returnnewDecimal(rounded).div(factor);}// 回退到 toPrecision(15)constsafeStrvalue.toPrecision(DEFAULT_CONFIG.numberPrecision);returnnewDecimal(safeStr);}thrownewError(Unsupported type for Decimal:${typeofvalue});}/** * 高精度加法 - 返回字符串 */functionadd(a,b,decimals){constresult_createDecimal(a).plus(_createDecimal(b));returnresult.toFixed(decimals||DEFAULT_CONFIG.defaultDecimals,Decimal.ROUND_HALF_UP);}/** * 高精度减法 - 返回字符串 */functionsubtract(a,b,decimals){constresult_createDecimal(a).minus(_createDecimal(b));returnresult.toFixed(decimals||DEFAULT_CONFIG.defaultDecimals,Decimal.ROUND_HALF_UP);}/** * 高精度乘法 - 返回字符串 */functionmultiply(a,b,decimals){constresult_createDecimal(a).times(_createDecimal(b));returnresult.toFixed(decimals||DEFAULT_CONFIG.defaultDecimals,Decimal.ROUND_HALF_UP);}/** * 高精度除法 - 返回字符串 */functiondivide(a,b,decimals){constdivisor_createDecimal(b);if(divisor.isZero()){thrownewError(Division by zero);}constresult_createDecimal(a).div(divisor);returnresult.toFixed(decimals||DEFAULT_CONFIG.defaultDecimals,Decimal.ROUND_HALF_UP);}/** * 格式化任意值为固定小数位字符串 */functionformat(value,decimals){constd_createDecimal(value);returnd.toFixed(decimals||DEFAULT_CONFIG.defaultDecimals,Decimal.ROUND_HALF_UP);}/** * 比较大小仍返回数字因为比较结果不需要字符串 * returns -1 (a b), 0 (a b), 1 (a b) */functioncompare(a,b){return_createDecimal(a).comparedTo(_createDecimal(b));}// 导出所有方法export{add,subtract,multiply,divide,format,compare};math.js 和 decimal 区别特性decimal.jsmath.js核心目标高精度十进制算术解决0.1 0.2 ≠ 0.3问题全能数学计算引擎支持符号计算、矩阵、复数、表达式解析等适用场景金融计算、金额处理、需要精确小数的业务科学计算、工程模拟、教育工具、复杂公式求解精度保证✅ 任意精度十进制可配置❌ 默认使用 JavaScript 原生number有浮点误差但可集成 decimal.js功能decimal.jsmath.js基础四则运算✅✅高精度小数✅❌除非集成 Decimal矩阵运算❌✅复数运算❌✅表达式解析如23*4❌✅符号计算代数❌✅单位换算kg → lb❌✅统计函数❌✅三角函数/对数等⚠️ 有限支持✅ 完整支持我喜欢的 number-precision (因为不会遇到特别高精度的东西)importNPfromnumber-precision;/** * 安全地将 number 转换为字符串避免精度表示问题 */function_safeToString(val){if(typeofval!number||!isFinite(val)){returnString(val);}if(Number.isInteger(val)){returnString(val);}// 使用 toPrecision(15) 保留 JS number 的最大安全精度returnparseFloat(val.toPrecision(15)).toString();}/** * 高精度加法 * param {...(number|string)} args * returns {number} */exportfunctionadd(...args){constprocessedargs.map(argtypeofargnumber?_safeToString(arg):String(arg));returnNP.plus(...processed);}/** * 高精度减法 * param {number|string} a * param {number|string} b * returns {number} */exportfunctionsub(a,b){returnNP.minus(typeofanumber?_safeToString(a):String(a),typeofbnumber?_safeToString(b):String(b));}/** * 高精度乘法 * param {number|string} a * param {number|string} b * returns {number} */exportfunctionmul(a,b){returnNP.times(typeofanumber?_safeToString(a):String(a),typeofbnumber?_safeToString(b):String(b));}/** * 高精度除法 * param {number|string} a * param {number|string} b * returns {number} */exportfunctiondiv(a,b){returnNP.divide(typeofanumber?_safeToString(a):String(a),typeofbnumber?_safeToString(b):String(b));}/** * 高精度四舍五入 * param {number|string} num * param {number} decimals - 保留小数位数 * returns {number} */exportfunctionround(num,decimals){returnNP.round(typeofnumnumber?_safeToString(num):String(num),decimals);}import{add,sub,mul,div,round}from./math-safe;// 示例处理后端传来的 number假设在安全范围内constprice19.9;consttaxRate0.1;consttaxmul(price,taxRate);// 1.99consttotaladd(price,tax);// 21.89constfinalround(total,2);// 21.89console.log(add(0.1,0.2));// 0.3 ✅console.log(sub(1.0,0.9));// 0.1 ✅

更多文章