javascript浮点数精度丢失是ieee 754双精度表示限制所致,非bug;应从源头规避:整数放大法(转整数运算再还原)、高精度库(如decimal.js传字符串)、大整数用字符串或bigint处理、容错比较与显示优化。

JavaScript 中浮点数运算精度丢失不是 bug,而是 IEEE 754 双精度浮点数在二进制下无法精确表示某些十进制小数(比如 0.1)的必然结果。所谓“补偿”,本质不是事后修正误差,而是从源头规避——用可控方式替代原生 Number 的直接运算。
整数放大法(适合金额、固定小数位场景)
把小数全部转为整数参与计算,全程避开浮点运算,最后再缩放还原。这是最轻量、最可靠的基础方案。
- 先确定所有操作数中最多的小数位数(如
19.99和0.005最多 3 位),放大倍数就是10 ** 小数位数 - 用
Math.round(num * factor)转整数,不能直接num * factor,否则放大过程就已引入新误差 - 整数间完成加减乘除,结果再除以相同倍数还原
- 注意放大后不能超过
Number.MAX_SAFE_INTEGER(约9e15),否则整数本身也会失真
高精度库(推荐用于金融、科学计算)
用字符串初始化 + 自定义十进制算法,彻底脱离 IEEE 754 限制。关键在于:必须传字符串,而非原始数字。
-
decimal.js:API 清晰、支持四舍五入模式和动态精度控制,例如
new Decimal('0.1').plus('0.2').toFixed(1) - bignumber.js:功能更全,适合复杂数学运算,如开方、幂运算等
- 配置合理精度(如
Decimal.set({ precision: 20 })),避免盲目设过高影响性能
大整数安全处理(应对 ID、时间戳等超范围值)
当数字超过 ±9007199254740991(2^53 - 1)时,Number 已无法准确表示,常见于后端 long 类型 ID 或毫秒级时间戳。
- 后端序列化时,将 long 字段转为字符串(如 Spring 中用
@JsonSerialize(using = ToStringSerializer.class)) - 前端接收后保持字符串形式传递或展示;仅在必要时用
BigInt计算(注意:BigInt不能与Number混用) - 避免
JSON.parse后直接对大数字做算术运算——这是精度丢失最常发生的入口
容错比较与显示优化(辅助手段,不替代核心逻辑)
在不需要精确计算、只做判断或展示的环节,可降低对原始数值精度的依赖。
- 比较两个浮点数是否“相等”时,用
Math.abs(a - b) 替代 <code>=== - 展示时用
.toFixed(n)或.toLocaleString()格式化,但注意它返回字符串,且toFixed在边界值上可能不符合数学四舍五入(如1.335.toFixed(2)得"1.33") - 减少连续浮点运算链,能合并的步骤尽量合并,避免误差层层累积
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











