Math 类提供了一些方法来进行精确的算术计算,并且当结果溢出时抛出一个异常。
static int multiplyExact(int x, int y) 返回参数的乘积,如果结果溢出 int,则抛出异常。
static long multiplyExact(long x, long y) 返回参数的乘积,如果结果溢出 long,则抛出异常。
例如:
int val = Math.multiplyExact(Integer.MAX_VALUE, Integer.MAX_VALUE); System.out.println(val); // java.lang.ArithmeticException: integer overflow
static int addExact(int x, int y) 返回参数之和,如果结果溢出一个 int,则抛出异常。
static long addExact(long x, long y) 返回参数之和,如果结果溢出 long,则抛出异常。
例如:
int val = Math.addExact(Integer.MAX_VALUE, Integer.MAX_VALUE); System.out.println(val); // java.lang.ArithmeticException: integer overflow
static int decrementExact(int a) 返回减一的参数,如果结果溢出一个 int,则抛出异常。
static long decrementExact(long a) 返回减一的参数,如果结果溢出 long,则抛出异常。
例如:
int val = Math.decrementExact(Integer.MIN_VALUE); System.out.println(val); // java.lang.ArithmeticException: integer overflow
static int incrementExact(int a) 返回参数的增量,如果结果溢出一个 int,则抛出异常。
static long incrementExact(long a) 返回参数的增量,如果结果溢出 long,则抛出异常。
例如:
int val = Math.incrementExact(Integer.MAX_VALUE); System.out.println(val); // java.lang.ArithmeticException: integer overflow
static int negateExact(int a) 返回参数的否定值,如果结果溢出一个 int,则抛出异常。
static long negateExact(long a) 返回参数的否定值,如果结果溢出 long,则抛出异常。
例如:
int val = Math.negateExact(Integer.MIN_VALUE); System.out.println(val); // java.lang.ArithmeticException: integer overflow
static int subtractExact(int x, int y) 返回参数的差值,如果结果溢出一个 int,则抛出异常。
static long subtractExact(long x, long y) 返回参数的差值,如果结果溢出 long,则抛出异常。
例如:
int val = Math.subtractExact(Integer.MIN_VALUE, 1); System.out.println(val); // java.lang.ArithmeticException: integer overflow
toIntExact 方法可以将一个 long 值转换为等价的 int 值。例如:
int val = Math.toIntExact(Long.MAX_VALUE); System.out.println(val); // java.lang.ArithmeticException: integer overflow
Math 的 floorMod 和 floorDiv 方法旨在解决一个长期存在的整型余数问题。以表达式 n₈2 为例,如果 n 为正数,n 为偶数则结果为 0, 而 n 为奇数则结果为 1。如果 n 为负数,则结果为 -1。为什么? 当第一台计算机诞生时,先驱们不得不为如何计算负数的整除和取余制定规则。数学家在几百年前就已经知道了最佳解 (或者“欧几里得”解): 永远保持余数大于等于0。但是,这些计算机先驱没有翻阅任何一本数学教材,而是得出了一个看似合理但实际却不方便的规则。
考虑一下这个问题。你需要计算时钟上时针的位置。你打算应用一个校正值,并希望将值限定 0 到 11 之间。这很容易:(position + adjustment) % 12。但是如果校正值是负数怎么办? 那样的话你可能会得到一个负数值。因此你不得不引入一个分支,或者使用 ((position +adjustment) % 12 +12) % 12。不管是哪种方式,都很麻烦。
新的 floorMod 方法使它变得很容易:floorMod(position +adjustment,12) 总是会返回一个 0 到 11 之间的值。
方法定义如下:
static int floorDiv(int x, int y) 返回小于或等于代数商的最大(最接近正无穷大)int 值。
static long floorDiv(long x, long y) 返回小于或等于代数商的最大(最接近正无穷大)long 值。
static int floorMod(int x, int y) 回 int 参数的底面模数。
static long floorMod(long x, long y) 返回长形参数的底面模数。
例如:
int val = Math.floorMod(10, 3); System.out.println("val = " + val); // val = 1 val = Math.floorDiv(10, 3); System.out.println("val = " + val); // val = 3
注意,不幸的是,对于负的除数,floorMod 会返回负数结果,例如:
int val = Math.floorMod(10, -3); System.out.println("val = " + val); // val = -2
但是实际中很少发生这样的情况。
Math 为 double 和 float 参数定义的 nextDown 方法会返回比指定数字小、但最接近于指定数字的浮点数字。定义如下:
static double nextDown(double d) 返回负无穷方向上与 d 相邻的浮点数值。
static float nextDown(float f) 返回负无穷方向上与 f 相邻的浮点数值。
例如:
float val = Math.nextDown(10.2f); System.out.println("val = " + val); // val = 10.199999