基于源码的个人理解 如有误解请指正
Java中直接用运算符进行加法操作,会产生溢出:
int a = Integer.MAX_VALUE;
int b = 1;
int c = a+b;
System.out.println(c-Integer.MIN_VALUE);
//output:0
说明a+b
产生了溢出,且值等于绝对值最大的负数,负2的31次方。
为了解决这个问题,Math类提供了一个不会溢出的加法:
public static int addExact(int x, int y) {
int r = x + y;
// HD 2-12 Overflow iff both arguments have the opposite sign of the result
if (((x ^ r) & (y ^ r)) < 0) {
throw new ArithmeticException("integer overflow");
}
return r;
}
原理其实很简单。只有两个正数或者两个负数相加的时候才会溢出,一正一负是不会溢出的。并且,溢出后得到的结果一定是与原值的符号相反的。
借用这个原理,(x ^ r) & (y ^ r)
将用运算符算出来的r与x和y分别异或。异或的规则是同0异1。我们只看符号位,如果符号位不同,那么两个括号得到的都是1。而与运算又是只有1 & 1
才是1,有一个为0都是0。因此,一旦溢出,无论是正溢出负溢出,(x ^ r) & (y ^ r)
计算出的结果都应该小于0
如果有用麻烦点个喜欢,对我是莫大的鼓励。