跳到内容

第 1 卷 / 第 3 章 / 第 2 课

3.2 算术、除法与余数 ​

前置知识:表达式、赋值与求值顺序

预计时间:25 分钟

完成标志:能预测正负整数除法、余数、溢出和自增副作用

基本算术与类型 ​

java
int left = 10;
int right = 3;

System.out.println(left + right); // 13
System.out.println(left - right); // 7
System.out.println(left * right); // 30
System.out.println(left / right); // 3
System.out.println(left % right); // 1

byte、short 和 char 参与普通算术时通常先提升为 int。表达式还可能溢出,类型不会因结果过大自动升级。

整数除法向零截断 ​

java
System.out.println(10 / 3);   // 3
System.out.println(-10 / 3);  // -3
System.out.println(10 / -3);  // -3
System.out.println(-10 / -3); // 3

“丢掉小数”只适合正数直觉;正式规则是商向零截断。

至少一个操作数为浮点类型时执行浮点除法:

java
System.out.println(10 / 3.0);        // 3.3333333333333335
System.out.println((double) 10 / 3); // 3.3333333333333335

赋给 double 不会倒推右侧运算:

java
double wrong = 10 / 3;   // 先得 int 3,再拓宽为 3.0
double right = 10 / 3.0;

整数除以零抛 ArithmeticException;浮点除以正零或负零按 IEEE 754 产生无穷或 NaN:

java
System.out.println(1.0 / 0.0); // Infinity
System.out.println(0.0 / 0.0); // NaN

还有一个整数边界:Integer.MIN_VALUE / -1 的数学结果超出 int,Java 返回 Integer.MIN_VALUE。Math.floorDiv 也不会检测这个溢出;在 Java 17 中应单独检查这一对输入,或先把操作数转为 long 再除。

% 是余数,不是总为非负的模 ​

Java 余数满足:

text
(a / b) * b + (a % b) == a

这里按 Java 的整数运算规则求值,并要求除数不为零。即使 MIN_VALUE / -1 溢出,该恒等式在 Java 的回绕运算下仍成立。非零余数的符号跟被除数一致:

java
System.out.println(7 % 3);   // 1
System.out.println(-7 % 3);  // -1
System.out.println(7 % -3);  // 1

因此判断奇数要写:

java
boolean odd = value % 2 != 0;

value % 2 == 1 会漏掉负奇数。

模数为正、需要落在 0..modulus-1 的循环索引时,使用:

java
int wrapped = Math.floorMod(index, 3);
java
System.out.println(-1 % 3);             // -1
System.out.println(Math.floorMod(-1, 3)); // 2

分页也要先定义编号口径。若条目从 0 开始,index / pageSize 是页索引;若业务编号从 1 开始,公式通常是 (number - 1) / pageSize。不要只贴一个 % 就称为通用分页。

自增和自减是带副作用的表达式 ​

java
int count = 5;
int before = count++; // before=5, count=6
int after = ++count;  // count=7, after=7
  • 后置 count++ 的表达式值是修改前的值,然后变量加一;
  • 前置 ++count 先修改变量,表达式值是修改后的值。

循环更新中 count++ 很常见。不要在同一复杂表达式里多次读写同一变量:

java
int result = count++ + ++count; // 规则确定,但维护成本高

拆开能保留意图:

java
int first = count;
count++;
count++;
int second = count;
int result = first + second;

溢出与 exact 方法 ​

java
int area = width * height;

即使 width 和 height 各自有效,乘积也可能溢出。需要失败而不是回绕时:

java
int area = Math.multiplyExact(width, height);

若先转 long:

java
long area = (long) width * height;

cast 必须在乘法之前;long area = width * height 会先以 int 计算并可能已经溢出。

专业速查 ​

场景规则
整数除法商向零截断
浮点除零无穷或 NaN,不抛整数除零异常
余数符号跟被除数
非负循环索引Math.floorMod,要求模数为正
负数奇偶value % 2 != 0
乘法升为 long运算前转换一个操作数
要检测溢出Math.*Exact 或显式边界检查
++/--简单更新可用,避免与其他副作用混合

离开这一页前 ​

用 -10 / 3、-7 % 3 和 Math.floorMod(-1, 3) 检验自己能否准确写出负数规则;再解释为什么 long result = intValue * otherInt 仍可能先溢出。

算术得到数值,程序还要把条件组合起来。

→ 下一步:比较、相等与短路逻辑

规范入口:JLS §15.17:乘除与余数、§15.14.2:后置自增。

Built with VitePress | Software Systems Atlas