【Java基础】5 / 2 为什么等于 2?整数除法、取余和 floorMod 一次讲清

【Java基础】5 / 2 为什么等于 2?整数除法、取余和 floorMod 一次讲清

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

🎬 博主名称: 超级苦力怕

🔥 个人专栏: 《基本功修炼大全》

🚀 每一次思考都是突破的前奏,每一次复盘都是精进的开始!


文章元信息:

  • 适合读者: 正在学习 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

52 默认都是 int 字面量,所以 5 / 2 执行的是整数除法,结果只能是整数。

想得到 2.5,必须在除法发生前,让至少一个操作数变成 doublefloat

最容易误解的是最后一行:

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 > 0r 来自 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 让一个操作数在除法前变成 doublefloat
整数除法怎么处理小数部分 向 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()。
相关推荐
fish_xk15 小时前
c++11(二)
java·前端·c++
星空15 小时前
跨域请求测试
java·java-ee
foundbug99915 小时前
实现MATLAB滚动轴承故障诊断
开发语言·matlab
gihigo199815 小时前
matlab实现三维四面体单元的有限元解法
开发语言·matlab
fengfuyao98515 小时前
Chen混沌系统 — 基于自适应控制的MATLAB仿真实现
开发语言·机器学习·matlab
yong999015 小时前
MATLAB的卷积码的编码和译码的实现
开发语言·matlab
宠友信息15 小时前
友猫社区Vue与Spring Boot多端社交平台源码架构
java·vue.js·spring boot·架构
love8888_cnsd15 小时前
Git & Linux 速查表
java·linux·git·后端·elasticsearch
不会C语言的男孩15 小时前
C++ Primer Plus 第2章:开始学习C++
开发语言·c++