【Java基础】5 / 2 为什么等于 2?整数除法、取余和 floorMod 一次讲清
-
- [一、`5 / 2` 为什么等于 `2`](#一、
5 / 2为什么等于2) - 二、整数除法不是向下取整
- [三、判断整除应该看 `%`](#三、判断整除应该看
%) - [四、`%` 的本质是求余,不是总为正的数学取模](#四、
%的本质是求余,不是总为正的数学取模) - [五、循环下标场景用 `Math.floorMod()`](#五、循环下标场景用
Math.floorMod()) - [六、容易漏掉的边界:`MIN_VALUE / -1`](#六、容易漏掉的边界:
MIN_VALUE / -1) - 七、常见误区汇总
- 八、总结
- [一、`5 / 2` 为什么等于 `2`](#一、

🎬 博主名称: 超级苦力怕
🔥 个人专栏: 《基本功修炼大全》
🚀 每一次思考都是突破的前奏,每一次复盘都是精进的开始!
文章元信息:
- 适合读者: 正在学习 Java 基础语法、运算符、类型转换,或经常被整数除法和负数取模结果绕晕的同学
- 前置知识: Java 基本数据类型、算术运算符、强制类型转换的基本写法
一、5 / 2 为什么等于 2
先看最经典的例子:
✅ 整数除法与浮点除法对比
java
System.out.println(5 / 2); // 2
System.out.println(5.0 / 2); // 2.5
System.out.println((double) 5 / 2); // 2.5
System.out.println((double) (5 / 2)); // 2.0
5 和 2 默认都是 int 字面量,所以 5 / 2 执行的是整数除法,结果只能是整数。
想得到 2.5,必须在除法发生前,让至少一个操作数变成 double 或 float。
最容易误解的是最后一行:
java
System.out.println((double) (5 / 2)); // 2.0
它不是先把整个算式变成浮点除法,而是先在括号里完成 5 / 2,得到整数 2,再把 2 转成 2.0。已经丢掉的 .5 不会再回来。
| 表达式 | 结果 | 关键点 |
|---|---|---|
5 / 2 |
2 |
int / int,执行整数除法 |
5.0 / 2 |
2.5 |
至少一个操作数是浮点类型 |
(double) 5 / 2 |
2.5 |
除法前先转操作数 |
(double) (5 / 2) |
2.0 |
先整数除法,后转结果 |
💡 核心结论: / 不只是数学除法,操作数类型会先决定执行整数除法还是浮点除法。
二、整数除法不是向下取整
整数除法不是四舍五入,也不是简单向下取整,而是向 0 截断。
✅ 正负数整数除法示例
java
System.out.println(5 / 2); // 2
System.out.println(-5 / 2); // -2
System.out.println(5 / -2); // -2
System.out.println(-5 / -2); // 2
关键是 -5 / 2。
数学结果是 -2.5。如果是向下取整,结果应该是 -3;但 Java 返回 -2,因为它是朝 0 的方向截断。
text
2.5 -> 2
-2.5 -> -2
同样,浮点数强转成 int 也不是四舍五入:
✅ 浮点数强转 int 示例
java
System.out.println((int) 86.7); // 86
System.out.println((int) -86.7); // -86
如果业务要表达明确的取整规则,应使用 Math.floor()、Math.ceil()、Math.round(),不要靠强转暗示。
⚠️ 误区:整数除法就是向下取整
正确理解: 对正数来说,向 0 截断和向下取整结果一样;对负数来说,两者可能不同。
三、判断整除应该看 %
如果问题是"100 能不能被 9 整除",不要看 100 / 9 有没有小数。
因为整数除法根本不会给你小数。
✅ 判断是否整除
java
System.out.println(100 % 10 == 0); // true
System.out.println(100 % 9 == 0); // false
可以封装成:
✅ 整除判断方法
java
public static boolean isDivisible(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("除数不能为 0");
}
return a % b == 0;
}
整数 / 和整数 % 遇到除数为 0 会抛出 ArithmeticException:
✅ 整数除以 0
java
System.out.println(5 / 0); // ArithmeticException: / by zero
System.out.println(5 % 0); // ArithmeticException: / by zero
但浮点除法不同,它会按 IEEE 754 规则得到特殊值:
✅ 浮点数除以 0
java
System.out.println(5.0 / 0); // Infinity
System.out.println(0.0 / 0); // NaN
💡 核心结论: 判断整除看 a % b == 0,不要用整数除法结果有没有小数来判断。
四、% 的本质是求余,不是总为正的数学取模
中文里经常把 % 叫"取模",但在 Java 中,它更准确地说是求余。
Java 的整数余数运算要满足这条关系:
text
(a / b) * b + (a % b) == a
这也是 Java 语言规范对整数余数运算的定义思路。
先看正数:
✅ 正数求余
java
System.out.println(5 / 2); // 2
System.out.println(5 % 2); // 1
// 5 == 2 * 2 + 1
再看负数:
✅ 负数求余
java
System.out.println(-5 / 2); // -2
System.out.println(-5 % 2); // -1
// -5 == (-2) * 2 + (-1)
所以,-5 % 2 在 Java 中是 -1,不是 1。
很多人会记成"% 的结果符号跟左操作数一致"。这个结论没错,但不要死记口诀:它本质上是由"整数除法向 0 截断"和上面的恒等式一起推出来的。
| 表达式 | Java % 结果 |
|---|---|
5 % 2 |
1 |
-5 % 2 |
-1 |
5 % -2 |
1 |
-5 % -2 |
-1 |
⚠️ 误区:
%的结果一定非负正确理解: Java 的
%是求余。被除数为负时,余数也可能为负。
五、循环下标场景用 Math.floorMod()
数组下标、星期偏移、环形队列这类场景,通常要的是非负循环余数。
这时不要直接相信 %。
✅ 循环下标示例
java
int index = 0;
int size = 7;
System.out.println((index - 1) % size); // -1
System.out.println(Math.floorMod(index - 1, size)); // 6
工程上建议把循环长度、数组长度这类除数明确约束为正数:
text
Math.floorMod(index, size) 中的 size 应满足 size > 0
如果 size <= 0,应先处理参数错误,不要把它交给取模逻辑。
Math.floorMod(a, m) 和 % 的核心差异是:它基于 floorDiv(),结果符号跟除数一致。当 m > 0 时,结果一定落在:
text
0 <= result < m
对比一下:
| 表达式 | 结果 |
|---|---|
-5 % 2 |
-1 |
Math.floorMod(-5, 2) |
1 |
5 % -2 |
1 |
Math.floorMod(5, -2) |
-1 |
-1 % 7 |
-1 |
Math.floorMod(-1, 7) |
6 |
如果不用 Math.floorMod(),常见手动修正是:
✅ 手动修正负余数
java
int r = a % m;
if (r < 0) {
r += m;
}
这段代码只适用于 m > 0 且 r 来自 Java 的 a % m。
因为 Java 余数满足 -m < r < m,所以负余数只要加一次 m,就会落回 [0, m)。
这个技巧依赖 Java % 的语义。移植到其他语言,或者你自己实现了一套除法/取模规则时,不要想当然照搬。
💡 核心结论: 循环下标优先写 Math.floorMod(index, size),并保证 size > 0。
六、容易漏掉的边界:MIN_VALUE / -1
除数为 0 会抛异常,这个大家通常知道。
更容易漏掉的是这个边界:
✅ Integer.MIN_VALUE 除以 -1
java
System.out.println(Integer.MIN_VALUE); // -2147483648
System.out.println(Integer.MIN_VALUE / -1); // -2147483648
System.out.println(Integer.MIN_VALUE % -1); // 0
数学上:
text
-2147483648 / -1 = 2147483648
但 2147483648 超过了 int 的最大值 2147483647。
Java 的处理不是抛异常,而是发生整数溢出,结果仍然等于 Integer.MIN_VALUE。
long 也一样:
✅ Long.MIN_VALUE 除以 -1
java
System.out.println(Long.MIN_VALUE / -1L); // -9223372036854775808
System.out.println(Long.MIN_VALUE % -1L); // 0
这个边界常出现在绝对值、反向排序、符号翻转、边界比较里。
尤其是:
✅ Math.abs 的边界
java
System.out.println(Math.abs(Integer.MIN_VALUE)); // -2147483648
不要把"取绝对值后一定非负"当成铁律。
⚠️ 误区:
Integer.MIN_VALUE / -1会抛异常正确理解: 不会。它会溢出并返回
Integer.MIN_VALUE。真正会抛异常的是整数除以0。
七、常见误区汇总
| 误区 | 正确理解 |
|---|---|
int / int 除不尽会自动转成 double |
不会,结果仍然是整数 |
(double) (5 / 2) 可以得到 2.5 |
不行,整数除法已经先得到 2 |
| 整数除法就是向下取整 | 不准确,Java 是向 0 截断 |
% 的结果一定非负 |
不一定,Java % 是求余 |
循环下标直接用 % 就够了 |
负数场景可能得到负下标,应考虑 Math.floorMod() |
Math.abs(Integer.MIN_VALUE) 一定非负 |
不一定,它仍然是 Integer.MIN_VALUE |
八、总结
| 问题 | 结论 |
|---|---|
5 / 2 为什么等于 2 |
两个操作数都是 int,执行整数除法 |
怎么得到 2.5 |
让一个操作数在除法前变成 double 或 float |
| 整数除法怎么处理小数部分 | 向 0 截断 |
| 怎么判断整除 | a % b == 0 |
-5 % 2 为什么是 -1 |
% 要满足 (a / b) * b + (a % b) == a |
| 想要非负循环余数怎么办 | size > 0 时使用 Math.floorMod(index, size) |
Integer.MIN_VALUE / -1 会怎样 |
不抛异常,溢出后仍是 Integer.MIN_VALUE |
最后压成三句话:
text
你以为 / 只是数学除法,其实操作数类型先决定规则。
你以为 % 是数学取模,其实它只负责把等式补完整。
你想要循环余数,答案是 size > 0 时的 Math.floorMod()。
