在 JavaScript 中,浮点数相加时因IEEE 754 双精度浮点数表示限制,常出现精度丢失问题(如0.1 + 0.2 = 0.30000000000000004)。以下是5 种核心解决方案及代码实现:
一、整数放大法(推荐简单场景)
将浮点数转换为整数运算,避免二进制精度问题。
实现步骤:
动态计算小数位数,确定放大倍数(如
10^n)。放大后转为整数相加,再缩小回原比例。
function addFloat(a, b) { const decimalPlaces = Math.max( (a.toString().split('.')[1]?.length || 0), (b.toString().split('.')[1]?.length || 0) ); const factor = Math.pow(10, decimalPlaces); return (Math.round(a * factor) + Math.round(b * factor)) / factor; } console.log(addFloat(0.1, 0.2)); // 0.3 console.log(addFloat(1.001, 2.002)); // 3.003优点:无需引入依赖,性能高。
缺点:需手动处理小数位数,大数可能溢出。
二、第三方高精度库(复杂计算必选)
使用decimal.js或bignumber.js等库,支持任意精度运算。
安装:
npm install decimal.js代码示例:
const Decimal = require('decimal.js'); function addFloat(a, b) { return new Decimal(a).plus(new Decimal(b)).toNumber(); } console.log(addFloat(0.1, 0.2)); // 0.3 console.log(addFloat(1.23e-10, 2.34e-10)); // 3.57e-10优点:支持复杂运算(如幂、开方),精度可控。
缺点:增加包体积,需学习 API。
三、字符串处理法(特定格式适用)
将数值转为字符串手动对齐小数位,模拟加法。
代码示例:
function addStringFloats(a, b) { const [intA, decA = ''] = a.split('.'); const [intB, decB = ''] = b.split('.'); const maxDecLength = Math.max(decA.length, decB.length); const paddedA = (parseInt(intA) * Math.pow(10, maxDecLength) + parseInt(decA.padEnd(maxDecLength, '0'))).toString(); const paddedB = (parseInt(intB) * Math.pow(10, maxDecLength) + parseInt(decB.padEnd(maxDecLength, '0'))).toString(); const result = (parseInt(paddedA) + parseInt(paddedB)) / Math.pow(10, maxDecLength); return result; } console.log(addStringFloats('0.1', '0.2')); // 0.3优点:完全避免浮点数误差。
缺点:实现复杂,性能较低。
四、toFixed 四舍五入(快速显示)
用toFixed格式化结果,适合展示场景。
const sum = 0.1 + 0.2; console.log(sum.toFixed(2)); // "0.30"(字符串) console.log(parseFloat(sum.toFixed(2))); // 0.3(数值)注意:
返回字符串,需手动转数值。
四舍五入可能引入误差(如
1.005→1.00)。
五、金融场景专用:整数单位存储
将金额以分 为单位存储,避免小数运算。
// 1元 = 100分 const addMoney = (a, b) => (Math.round(a * 100) + Math.round(b * 100)) / 100; console.log(addMoney(0.1, 0.2)); // 0.3 console.log(addMoney(19.99, 0.01)); // 20.00优点:绝对精度,适合金融计算。
缺点:需业务逻辑适配单位转换。
方法对比与选型建议
方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
整数放大法 | 简单加减运算 | 无需依赖,性能高 | 需处理小数位数,溢出风险 |
第三方库(如decimal.js) | 复杂计算、金融/科学场景 | 高精度,功能丰富 | 增加包体积 |
字符串处理法 | 特定格式输入(如固定小数位) | 完全避免误差 | 实现复杂,性能低 |
toFixed | 结果展示 | 快速格式化 | 四舍五入误差,类型转换 |
整数单位存储 | 金融金额计算 | 绝对精度,零误差 | 业务逻辑需适配 |
总结
简单场景:优先用整数放大法 或第三方库。
金融场景:采用整数单位存储(如分)。
展示需求:结合
toFixed控制显示精度。复杂计算:必选
decimal.js或bignumber.js。
通过合理选型,可有效解决浮点数精度问题,避免因误差导致的业务逻辑错误。