Math.round(double) 返回 (long)Math.floor(a + 0.5),对所有有限 a 成立;正数 .5 向上取整(如 2.5→3),负数 .5 向零取整(如 -2.5→-2),导致整体正向偏移。
math.round() 本身不直接返回 long,而是对 double 返回 long(对 float 返回 int),其四舍五入规则是“向正无穷方向舍入到最近的整数,.5 的情况统一向上取整”——但需特别注意:它实际执行的是 floor(x + 0.5)(对非负数成立),而对负数有细微差异。这导致中间值(如 x.5)在正负两侧并非严格对称偏移。
Math.round(double) 的真实行为
Java 中 Math.round(double a) 等价于:
(long)Math.floor(a + 0.5d) —— 仅当 a >= -0.5 时成立;
更准确的定义是:返回参数加 0.5 后向下取整的 long 值,即:Math.round(a) == (long)Math.floor(a + 0.5) 对所有有限 a 成立(JDK 源码证实)。
关键点:
- 它不是“银行家舍入”(偶数舍入),也不是简单比较小数位;
- 对正数:2.5 → 3,3.5 → 4(全部 .5 向上);
- 对负数:-2.5 → -2(因为
floor(-2.5 + 0.5) = floor(-2.0) = -2),而 -1.5 → -1; - 因此,.5 类型的中间值在负数侧“偏向零”,正数侧“远离零”,整体产生**正向偏移**(统计上使结果系统性偏大)。
double → long 四舍五入的推荐写法
若你明确要“数学上标准的四舍五入”(即绝对值意义下距离最近的整数,.5 时向偶数舍入或统一向上),Math.round() 并不满足后者。常用安全方式:
-
保持 Math.round 行为(默认推荐):直接用
Math.round(d),它已高效、无溢出风险,且语义清晰——“最常见的四舍五入”(多数人预期的 .5 进一); -
避免 double 表示误差影响:如
2.4999999999999996实际是2.5 - ε,Math.round()会得 2;必要时可加极小扰动(慎用):Math.round(d + 1e-15); -
需要银行家舍入(IEEE 754 roundTiesToEven):用
BigDecimal:new BigDecimal(Double.toString(d)).setScale(0, RoundingMode.HALF_EVEN).longValue(); -
手动实现 floor(x + 0.5) 风格(仅限非负):若确定
d >= 0,可用(long)(d + 0.5),但注意d接近Long.MAX_VALUE时可能溢出转负——Math.round()内部已处理边界,更安全。
中间值偏移的实际影响与验证
考虑区间 [-10.5, 10.5] 内所有 x.5 值(共 21 个):
Math.round 映射为:
-10.5→-10, -9.5→-9, ..., -0.5→0, 0.5→1, 1.5→2, ..., 10.5→11
偏移量(round(x) − x)在 x = n.5 处恒为 +0.5(n ≥ 0),但对 n
-2.5 → -2 ⇒ 偏移 = (-2) − (-2.5) = +0.5
-0.5 → 0 ⇒ 偏移 = 0 − (-0.5) = +0.5
所以所有 x.5 的偏移**恰好都是 +0.5** —— 这正是 floor(x + 0.5) − x 在 x 为半整数时的必然结果。
结论:Math.round 对所有 .5 值引入固定 +0.5 偏移,无正负不对称;所谓“负数侧偏向零”是结果表象,偏移量本身一致。
注意事项与陷阱
-
Double.NaN、Infinity输入时,Math.round()返回0或Long.MIN_VALUE/MAX_VALUE,需提前校验; - 不要用
(long)Math.round(d)——Math.round(double)已返回long,重复强转无意义; - 对比
(long)Math.ceil(d)或(long)Math.floor(d):它们不处理四舍五入,仅单向截断; - 性能上,
Math.round()是 JVM 内建优化方法,比BigDecimal快 100 倍以上,日常精度要求下应优先使用。

















