一、方法定义
Math.floorMod()
是 Java 标准库 java.lang.Math
类中的一个静态方法,用于执行向下取整的模运算(floor modulus),返回结果始终为非负数或零。
方法签名:
public static int floorMod(int x, int y)
public static long floorMod(long x, long y)
- 参数:
x
:被除数(dividend)y
:除数(divisor),不能为 0
- 返回值:
- 返回
x
对y
的“向下取整模运算”结果,类型为int
或long
- 返回
- 异常:
ArithmeticException
:当y == 0
时抛出
二、功能说明
floorMod
的核心目标是解决传统 %
运算符在处理负数时结果符号不确定的问题。
与 %
运算符的关键区别:
运算方式 | 行为 |
---|---|
% (remainder) |
结果的符号与被除数(x)相同 |
floorMod |
结果始终 ≥ 0(当 y > 0 时) |
数学定义:
floorMod(x, y)
等价于:
x - (floorDiv(x, y) * y)
其中 floorDiv(x, y)
是向下取整的除法(Math.floorDiv(x, y)
)。
✅ 最终结果满足:
0 <= floorMod(x, y) < |y|
三、示例代码
1. 基本用法对比 %
与 floorMod
public class FloorModExample {
public static void main(String[] args) {
int divisor = 5;
// 正数情况:两者结果相同
System.out.println("13 % 5 = " + (13 % 5)); // 3
System.out.println("Math.floorMod(13, 5) = " + Math.floorMod(13, 5)); // 3
// 负数被除数:关键差异!
System.out.println("-13 % 5 = " + (-13 % 5)); // -3
System.out.println("Math.floorMod(-13, 5) = " + Math.floorMod(-13, 5)); // 2
// 负除数
System.out.println("13 % -5 = " + (13 % -5)); // 3
System.out.println("Math.floorMod(13, -5) = " + Math.floorMod(13, -5)); // -2
// 双负数
System.out.println("-13 % -5 = " + (-13 % -5)); // -3
System.out.println("Math.floorMod(-13, -5) = " + Math.floorMod(-13, -5)); // -3
}
}
输出结果:
13 % 5 = 3
Math.floorMod(13, 5) = 3
-13 % 5 = -3
Math.floorMod(-13, 5) = 2
13 % -5 = 3
Math.floorMod(13, -5) = -2
-13 % -5 = -3
Math.floorMod(-13, -5) = -3
🔍 重点:当
y > 0
时,floorMod
结果始终在[0, y)
范围内,非常适合数组索引、循环周期等场景。
四、使用技巧
1. 安全的数组索引循环(环形缓冲区)
int[] buffer = new int[5];
int index = -1; // 用户输入或计算可能为负
// 安全获取循环索引
int safeIndex = Math.floorMod(index, buffer.length); // 若 index=-1, 结果为 4
buffer[safeIndex] = 100;
2. 时间计算(如计算星期几)
// 假设今天是星期三(0=周日, 1=周一, ..., 6=周六)
int today = 3;
int daysAgo = 10;
// 计算 10 天前是星期几
int dayOfWeek = Math.floorMod(today - daysAgo, 7);
System.out.println("10天前是星期" + dayOfWeek); // 输出: 5 (周五)
3. 哈希环或一致性哈希中的节点选择
int nodeCount = 8;
int hashValue = -123456; // 哈希值可能为负
int nodeIndex = Math.floorMod(hashValue, nodeCount);
System.out.println("分配到节点: " + nodeIndex); // 保证在 [0,7] 范围内
五、常见错误
❌ 错误1:认为 floorMod
总是返回正数
System.out.println(Math.floorMod(13, -5)); // 输出: -2(负数!)
✅ 规则:结果符号与除数 y 相同。只有当
y > 0
时,结果才 ≥ 0。
❌ 错误2:除数为 0
Math.floorMod(10, 0); // 抛出 ArithmeticException: / by zero
✅ 必须确保
y != 0
。
❌ 错误3:混淆 floorMod
与 %
// 错误假设
if (n % 5 == 3) { ... }
// 与
if (Math.floorMod(n, 5) == 3) { ... }
// 当 n 为负数时,行为不同!
六、注意事项
项目 | 说明 |
---|---|
结果范围 | 0 <= r < |y| 当 y > 0 ;0 >= r > -|y| 当 y < 0 |
性能 | 比 % 略慢(因额外计算),但差异极小 |
浮点数不支持 | 无 double /float 版本 |
溢出情况 | 极少见,如 floorMod(Integer.MIN_VALUE, -1) 可能溢出 |
与 floorDiv 关系 | x == floorDiv(x,y)*y + floorMod(x,y) 恒成立 |
七、最佳实践
- ✅ 周期性计算优先使用:如数组索引、时间计算、循环调度等。
- ✅ 替代负数取模的复杂逻辑:避免手动写
(x % y + y) % y
。 - ✅ 明确意图:使用
floorMod
表明你需要“非负余数”。 - ✅ 配合
floorDiv
:需要向下取整除法时,两者成对使用。
✅ 推荐替代写法:
// 旧写法(易错)
int mod = ((x % y) + y) % y;
// 新写法(清晰安全)
int mod = Math.floorMod(x, y);
八、性能优化建议
场景 | 建议 |
---|---|
确定 x ≥ 0 | 直接使用 x % y ,性能更优 |
高频调用 | floorMod 性能良好,通常无需优化 |
常量除数 | JIT 可能优化,无需手动展开 |
浮点需求 | 使用 Math.IEEEremainder() 或自定义逻辑 |
九、总结
项目 | 内容 |
---|---|
核心功能 | 实现向下取整模运算,解决负数取模符号问题 |
关键优势 | 当 y > 0 时,结果始终在 [0, y) 范围内 |
适用场景 | 数组索引、周期计算、哈希分配、时间逻辑 |
与 % 区别 |
% 是余数运算,符号随被除数;floorMod 是数学模运算 |
最佳实践 | 用于需要非负余数的场景,替代 (x%y+y)%y 冗余写法 |
注意事项 | 除数不能为 0;结果符号与除数相同 |
✅ 一句话掌握:
Math.floorMod(x, y)
返回x
除以y
的非负余数(当y > 0
时),是处理循环、索引等场景的安全首选。