JavaScript Math.round 的负半数:1.5 变成 2,为什么 -1.5 却变成 -1
把偏移量舍入到整数格点时,正的一点五得到二,负的一点五却得到负一。如果预期正负两侧保持对称,这个结果会显得奇怪。Math.round 在两侧距离相等时选择更接近正无穷的整数,因此负半数也向数轴右边走。
先分清两个阶段:通常选择距离最近的整数;只有恰好处在中点时,才使用平局规则。下面保存为 demo.mjs,用 node demo.mjs 运行,所有样本固定在内存中,使用 Node.js 自带断言验证。
AI模型生成概念示意:处在相邻整数之间的中点统一向右侧选择;非实测截图,点位只说明方向。
import assert from "node:assert/strict";
const show = value => Object.is(value, -0) ? "-0" : String(value);
const halves = [-2.5, -1.5, -0.5, 0.5, 1.5, 2.5];
const rounded = halves.map(Math.round);
assert.deepEqual(rounded, [-2, -1, -0, 1, 2, 3]);
console.log("halves:", halves.join(","));
console.log("rounded:", rounded.map(show).join(","));
const near = [-1.6, -1.4, 1.4, 1.6].map(Math.round);
assert.deepEqual(near, [-2, -1, 1, 2]);
console.log("nearest:", near.join(","));
const direct = Math.round(-1.5);
const signAfter = -Math.round(1.5);
assert.equal(direct, -1);
assert.equal(signAfter, -2);
console.log("direct/sign-after:", direct, signAfter);
assert.ok(Object.is(Math.round(-0.5), -0));
assert.ok(Object.is(Math.floor(-0.5 + 0.5), 0));
console.log("round/floor-plus-half:", show(Math.round(-0.5)),
show(Math.floor(-0.5 + 0.5)));用正负配对样本确定规则
第一行 halves 是 -2.5,-1.5,-0.5,0.5,1.5,2.5,第二行 rounded 是 -2,-1,-0,1,2,3。负二点五在负三与负二之间,两个距离都是零点五,较大的负二获选。这里“向正无穷”指平局的取舍方向,不表示所有数都直接向上取整。
第三行 nearest 为 -2,-1,1,2,对应负一点六、负一点四、正一点四与正一点六。它们不在中点,所以直接选择较近的一侧。若把 Math.round 换成 Math.ceil,负一点六会得到负一;若换成 Math.floor,正一点六又会得到一,意义都已改变。
第四行 direct/sign-after: -1 -2 对照直接舍入负一点五,与先舍入正一点五再加负号。第二种做法把正半数向外取整后镜像到负侧,已经换成另一套平局规则。不能把这一改写当作不影响语义的整理或优化。
让业务明确需要哪种平局处理
界面格点、统计汇总和测量结果可能有不同的平局要求。需求只写“四舍五入”时,应补上正负一点五以及正负二点五的预期结果,再选择实现。这样才能区分向正无穷、远离零和取最近偶数等规则,不必靠函数名称猜测。
最后一行 round/floor-plus-half: -0 0 是补充边界:Math.round 在负零点五返回负零,而先加零点五再 floor 得到正零。show 函数只让输出清楚显示符号。这个区别说明常见的“先加半再向下取整”并非对所有输入都与内建方法完全等价。
示例选择的半数能被二进制浮点精确表示,目的是单独观察平局规则。如果把十进制小数先乘一百再舍入,乘法结果可能已略偏离你想象的中点;那又是输入表示和运算精度的问题,不能只修改正负方向便认为彻底解决。
本文验证整数舍入,不提供任意十进制位数的金额算法。需要精确十进制契约时,应明确数据表示、缩放时机和舍入模式,并用边界样本验证。还应拒绝或单独处理不属于业务范围的 NaN、无穷大和非数值输入。
资料核对日期:2026年10月2日。最终展示代码在 Node.js v24.19.0 独立运行并通过全部断言;结果对应文中固定输入。


