number.epsilon 是用于构建可靠数值比较逻辑的底层基准值,可避免浮点误差导致的迭代收敛误判、几何相交漏检等问题,但不适用于金融计算、大整数运算和极小数场景。

Number.EPSILON 不是“通用精度开关”,而是一个用于构建**可靠数值比较逻辑**的底层基准值。它在数值算法中真正起作用的地方,是帮你避开浮点误差导致的逻辑断裂——比如迭代收敛误判、几何相交漏检、物理碰撞失灵等。用错方式反而会让算法更不稳定。
判断迭代是否收敛
很多数值算法(如牛顿法、梯度下降、求解非线性方程)依赖「前后两次结果变化足够小」作为停止条件。若直接写 Math.abs(x1 - x0) ,可能在不同量级下失效:
- 当解接近 0(如残差为 1e-15),1e-10 过大,提前终止
- 当解是 1e8(如天文模拟中的距离),1e-10 又太小,可能死循环
正确做法是结合相对变化与 EPSILON:
function isConverged(a, b, relTol = 10 * Number.EPSILON) {
const diff = Math.abs(a - b);
const scale = Math.max(Math.abs(a), Math.abs(b), 1e-15); // 防零除
return diff <p>这样既适应大小数,又保留了双精度机器本身的分辨能力参考。</p><h3>几何计算中的容差判定</h3><p>在 2D/3D 图形或物理引擎中,常需判断点是否在直线上、线段是否相交、平面是否共面。这些运算大量涉及叉积、点积和行列式,结果理论上应为 0,但浮点下常为 ±1e-16。</p>
- 错误写法:
cross === 0或Math.abs(cross) (仅对单位向量有效) - 推荐写法:按输入向量长度缩放容差
const tol = Number.EPSILON * Math.max(lenA, lenB) * Math.max(lenA, lenB);
因叉积量级与向量长度乘积正相关,容差也需同步放大
例如 Three.js 内部判断三点共线时,就采用类似带尺度的阈值,而非固定 EPSILON。
避免因精度引发的逻辑分支错误
某些算法依赖「严格大于」「严格小于」做分支,比如:
- 排序比较函数返回负数/正数决定顺序
- 凸包算法中按极角排序,角度相等时需 fallback 到距离
- 光线追踪中判断交点是否在物体表面「前方」
若直接用 a > b,微小误差可能导致同一组数据在不同运行中排序不一致(违反稳定排序要求)。应改用带容差的三值比较:
function compare(a, b) {
const diff = a - b;
if (Math.abs(diff) 0 ? 1 : -1;
}
这能保证数值上“不可分辨”的输入产生确定性结果。
不适用的场景要主动绕开
EPSILON 是浮点工具,不是精度救星。以下情况它帮不上忙,硬套反而出问题:
-
金融计算:一分钱都不能错 → 改用整数分或
BigInt,或专用库如decimal.js -
大整数运算(>253):此时相邻可表示数间隔已远超 EPSILON,比如
Math.pow(2, 53) + 1 === Math.pow(2, 53)恒为 true - 极小数(:EPSILON 比数值本身还大,所有比较都退化为恒等
-
字符串转数字后的校验:如
Number('0.1') + Number('0.2') === Number('0.3')依然失败 → 应从源头用字符串或 Decimal 构造
真正稳健的数值算法,从来不是靠一个常量兜底,而是根据量级、业务语义和误差传播路径,设计分层容差策略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











