
Math.round 为什么 -2.5 变成 -2 而不是 -3?
因为 Math.round(double) 的真实逻辑是 Math.floor(x + 0.5),不是“四舍五入”字面意思的数学规则。负数加 0.5 后再向下取整,导致边界行为反直觉。
-
Math.round(-2.5)→ 先算-2.5 + 0.5 = -2.0,再Math.floor(-2.0) = -2.0→ 强转为long得-2 -
Math.round(-2.6)→-2.6 + 0.5 = -2.1→Math.floor(-2.1) = -3.0→ 结果是-3 - 对
float参数,返回int;对double,返回long—— 类型不一致容易引发隐式截断或编译错误 - 别用
Math.round(x * 100) / 100.0做保留两位小数:浮点误差会让1.235变成1.23或1.24不稳定
Math.ceil 和 Math.floor 处理负数时方向容易搞反
Math.ceil() 是“向正无穷取整”,Math.floor() 是“向负无穷取整”,不是简单去掉小数部分。负数场景下,它们的结果常和直觉相反。
-
Math.ceil(-2.3)→-2.0(向上,即更靠近 0),不是-3.0 -
Math.floor(-2.3)→-3.0(向下,即更远离 0) - 如果想实现“截断小数”(即向零取整),这两个都不行:
(int)-2.7才得-2,但会丢失精度且不适用于大数(溢出风险) - 注意返回值全是
double类型,哪怕输入是int,比如Math.ceil(5)返回5.0,直接赋给int需显式强转
该用哪个方法?看你的业务语义而不是名字
别被“向上”“向下”“四舍五入”这几个词带偏——先明确你要解决的实际问题,再匹配函数语义。
- 分页计算总页数(如 23 条数据、每页 10 条 → 要 3 页):用
Math.ceil((double)total / size) - 计算文件块索引(第 123 字节在第几块,块大小 64):用
Math.floor((double)pos / blockSize) - 金额展示四舍五入到分(元为单位):别用
Math.round(amount * 100) / 100.0,改用BigDecimal;若坚持用 double,请先加Math.ulp(amount)抗误差 - 做数组索引偏移(比如跳过前 0.7 个元素):用
Math.floor()确保不越界;用Math.ceil()可能跳过太多
round 与 floor/ceil 的类型陷阱和性能差异
Math.round() 返回整数类型(int 或 long),而 ceil/floor 固定返回 double,这影响后续计算链和泛型推导。
立即学习“Java免费学习笔记(深入)”;
- 连续调用如
Math.round(Math.ceil(x))是冗余的,且可能因 double → long → double 隐式转换引入精度丢失 - 在高频循环中(如图形渲染、信号处理),
Math.floor()和Math.ceil()通常比Math.round()略快,因为后者多一次加法和一次 floor - JVM 对这三个方法做了 intrinsic 优化,但前提是参数是原始类型;如果传的是包装类(如
Double),会触发自动拆箱,带来额外开销 - Android API 26+ 才完全支持
Math.round(float)的硬件加速,旧版本建议用(int)Math.floor(x + 0.5f)替代(需自行处理负数)
实际开发里最常翻车的,是把 Math.round() 当成纯数学四舍五入来用,又忽略它对负数的特殊处理;还有人以为 Math.floor(-0.1) 是 0,结果发现是 -1.0 —— 这些都不是 bug,是定义如此。








