<p>JavaScript 的 Number 类型基于 IEEE 754 双精度浮点数标准,无法精确表示很多十进制小数(如 0.1),因此 0.1 + 0.2 === 0.30000000000000004 是设计使然,不是 bug。处理的关键是绕过限制,而非修复 Number——用更可控的方式替代原生浮点运算。整数放大法(适合金额、固定小数位)把小数转为整数计算,全程避开浮点运算,最后还原。轻量、可靠,适用于价格、库存、百分比等场景。先统计所有操作数最多的小数位数(如 19.99 和 0.005 最多 3 位),放大倍数为 10 3 === 1000,用 Math.round(num factor) 转整数——不能直接 num factor,否则放大过程就已失真;加减乘除全在整数间进行;除法结果若需保留小数,建议用高精度库或手动截断;注意:放大后数值不能超过 Number.MAX_SAFE_INTEGER(约 9e15),否则整数本身也会溢出失真。引入高精度库(推荐金融/科学计算):用字符串初始化 + 十进制算法模拟,</p>

JavaScript 的 Number 类型基于 IEEE 754 双精度浮点数标准,无法精确表示很多十进制小数(如 0.1),因此 0.1 + 0.2 === 0.30000000000000004 是设计使然,不是 bug。处理的关键是**绕过限制,而非修复 Number**——用更可控的方式替代原生浮点运算。
整数放大法(适合金额、固定小数位)
把小数转为整数计算,全程避开浮点运算,最后还原。轻量、可靠,适用于价格、库存、百分比等场景。
- 先统计所有操作数最多的小数位数(如
19.99和0.005最多 3 位),放大倍数为10 ** 3 === 1000 - 用
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)→'0.3' -
bignumber.js:功能更全,支持开方、幂、三角函数等
BigNumber.config({ DECIMAL_PLACES: 10 })设置全局精度 - 避免
new Decimal(0.1)这类写法——误差已在输入时固化
大整数安全处理(应对 ID、时间戳)
当整数超过 ±9007199254740991(2^53 - 1)时,Number 已无法准确表示,常见于后端 long 型 ID 或毫秒级时间戳。
- 后端序列化时,将超长数字字段转为字符串(如 Spring 中用
@JsonSerialize(using = ToStringSerializer.class)) - 前端接收后保持字符串形式传递或展示;仅在必要时用
BigInt计算(如BigInt("9007199254740993") + 1n) - 禁止
JSON.parse()后直接对大数字做算术运算——这是精度丢失最典型的入口
容错比较与显示优化(辅助手段)
不解决根本问题,但能缓解展示和判断环节的困扰。
- 判断“相等”时,用
Math.abs(a - b) 替代 <code>a === b - 格式化显示可用
.toFixed(n)或.toLocaleString(),但注意:
– 它返回字符串,不是数字
–toFixed在边界值上可能不符合数学四舍五入(如1.335.toFixed(2)得"1.33") - 减少连续浮点运算链,能合并的步骤尽量合并,防止误差层层累积


















