JavaScript中Math.ceil异常进位问题:为何不同小数位数结果不同?
为什么这两段JavaScript代码的执行结果有差异?
这本质上是IEEE 754双精度浮点数的精度限制在搞鬼——JavaScript里所有数字都是这种类型,而不是所有十进制小数都能被精确转换成二进制浮点数。
拆解第一个例子:Math.ceil(1.22222 * 100000)
你以为1.22222是一个精确数值,但实际上它在JavaScript内存里是一个近似值。二进制浮点数无法精确表示像0.1、0.00001这类十进制小数,存储的数值会比真实的1.22222稍微大一点点。
当你把这个近似值乘以100000之后,结果就变成了一个比122222略大的数(实际打印出来可能是122222.00000000002)。而Math.ceil()的作用是向上取整,哪怕这个数只比122222大一丝丝,也会被取整成122223,这就是结果不符合预期的原因。
拆解第二个例子:Math.ceil(1.222222 * 1000000)
巧合的是,1.222222的二进制近似值,在乘以1000000之后,刚好被存储成了精确的1222222(或者误差小到浮点数无法区分,直接被当成整数)。所以Math.ceil()对这个整数取整,自然就得到了预期的1222222。
验证方法
你可以直接在控制台打印这两个乘法的结果,就能直观看到差异:
console.log(1.22222 * 100000); // 输出 122222.00000000002 console.log(1.222222 * 1000000); // 输出 1222222
解决这类问题的小技巧
如果需要精确的十进制运算,避免浮点数误差,可以:
- 把小数转换成整数再计算(比如把
1.22222当成122222,除以100000的操作放到最后) - 用
Number.EPSILON做微小修正,比如:Math.ceil((1.22222 * 100000) - Number.EPSILON) - 对于复杂的精确计算,考虑使用专门的十进制运算库(简单场景前两种方法足够)
内容的提问来源于stack exchange,提问作者ldsenow
相关产品推荐
相关产品推荐

