JavaScript中Number类型基于IEEE 754双精度浮点数实现,无法精确表示大多数十进制小数,如0.1+0.2≠0.3;因其二进制表示为无限循环小数,存储时被截断导致误差;仅整数≤2⁵³−1且小数为1/2ⁿ有限和的数可精确表示;实际应使用容差比较或转换策略。

JavaScript 中的 Number 类型基于 IEEE 754 双精度浮点数(64 位)实现,这意味着它**无法精确表示所有十进制小数**,尤其在加减乘除等基本运算中容易出现意料之外的“误差”,比如 0.1 + 0.2 === 0.3 返回 false。
为什么 0.1 + 0.2 不等于 0.3?
因为十进制小数 0.1 和 0.2 在二进制中是无限循环小数(类似十进制中 1/3 = 0.333…),而双精度浮点数只能存储有限位数(53 位有效数字),系统必须截断或舍入,导致存储值本身就有微小偏差。相加后误差叠加,结果就变成了 0.30000000000000004。
哪些数值能被精确表示?
只有满足以下条件的十进制数才能在 Number 中无损存储:
- 整数部分 ≤ 253 − 1(即
9007199254740991),且为整数; - 小数部分是
1 / (2<sup>n</sup>)的有限和,例如0.5(1/2)、0.75(1/2 + 1/4)、0.125(1/8); - 像
0.1、0.2、0.3、0.01这类常见十进制小数,基本都不能精确表示。
实际开发中怎么应对精度问题?
不依赖 === 直接比较浮点结果,改用容差判断或转换策略:
立即学习“Java免费学习笔记(深入)”;
-
比较时用 epsilon 容差:如
Math.abs(a - b) (推荐用于一般比较); - 金融计算转整数运算:把元换算成分(×100),全程用整数加减,最后再除以 100 显示;
-
使用 toFixed 需谨慎:它返回字符串,且四舍五入逻辑在某些版本中存在差异(如
(0.615).toFixed(2)可能得"0.61"或"0.62"),建议配合parseFloat或专用库; -
复杂场景用专门库:如
decimal.js、big.js或bn.js,它们提供任意精度的十进制运算支持。
一个容易忽略的细节:Number.MAX_SAFE_INTEGER
超过 2<sup>53</sup> − 1 的整数无法被唯一表示——相邻两个可表示的数之间间隔大于 1。例如:
9007199254740991 === 9007199254740992 返回 true,这不是 bug,而是浮点数设计的必然限制。处理大整数应考虑 BigInt(注意:BigInt 不能与 Number 混合运算)。










