Java如何处理整数下溢和溢出?
在此基础上,你将如何检查/测试这种情况的发生?
Java如何处理整数下溢和溢出?
在此基础上,你将如何检查/测试这种情况的发生?
当前回答
我自己也遇到了这个问题,下面是我的解决方案(包括乘法和加法):
static boolean wouldOverflowOccurwhenMultiplying(int a, int b) {
// If either a or b are Integer.MIN_VALUE, then multiplying by anything other than 0 or 1 will result in overflow
if (a == 0 || b == 0) {
return false;
} else if (a > 0 && b > 0) { // both positive, non zero
return a > Integer.MAX_VALUE / b;
} else if (b < 0 && a < 0) { // both negative, non zero
return a < Integer.MAX_VALUE / b;
} else { // exactly one of a,b is negative and one is positive, neither are zero
if (b > 0) { // this last if statements protects against Integer.MIN_VALUE / -1, which in itself causes overflow.
return a < Integer.MIN_VALUE / b;
} else { // a > 0
return b < Integer.MIN_VALUE / a;
}
}
}
boolean wouldOverflowOccurWhenAdding(int a, int b) {
if (a > 0 && b > 0) {
return a > Integer.MAX_VALUE - b;
} else if (a < 0 && b < 0) {
return a < Integer.MIN_VALUE - b;
}
return false;
}
如果有错误或者可以简化,请随意纠正。我已经用乘法法做了一些测试,大部分是边缘情况,但它仍然可能是错误的。
其他回答
它什么都不做——只是发生了under/overflow。
“-1”是溢出计算的结果,与任何其他信息产生的“-1”没有区别。因此,您不能通过某些状态或仅仅检查一个值来判断它是否溢出。
但是为了避免溢出,你可以聪明地进行计算,如果这很重要的话,或者至少知道什么时候会发生溢出。你的情况如何?
static final int safeAdd(int left, int right)
throws ArithmeticException {
if (right > 0 ? left > Integer.MAX_VALUE - right
: left < Integer.MIN_VALUE - right) {
throw new ArithmeticException("Integer overflow");
}
return left + right;
}
static final int safeSubtract(int left, int right)
throws ArithmeticException {
if (right > 0 ? left < Integer.MIN_VALUE + right
: left > Integer.MAX_VALUE + right) {
throw new ArithmeticException("Integer overflow");
}
return left - right;
}
static final int safeMultiply(int left, int right)
throws ArithmeticException {
if (right > 0 ? left > Integer.MAX_VALUE/right
|| left < Integer.MIN_VALUE/right
: (right < -1 ? left > Integer.MIN_VALUE/right
|| left < Integer.MAX_VALUE/right
: right == -1
&& left == Integer.MIN_VALUE) ) {
throw new ArithmeticException("Integer overflow");
}
return left * right;
}
static final int safeDivide(int left, int right)
throws ArithmeticException {
if ((left == Integer.MIN_VALUE) && (right == -1)) {
throw new ArithmeticException("Integer overflow");
}
return left / right;
}
static final int safeNegate(int a) throws ArithmeticException {
if (a == Integer.MIN_VALUE) {
throw new ArithmeticException("Integer overflow");
}
return -a;
}
static final int safeAbs(int a) throws ArithmeticException {
if (a == Integer.MIN_VALUE) {
throw new ArithmeticException("Integer overflow");
}
return Math.abs(a);
}
有一种情况,上面没有提到:
int res = 1;
while (res != 0) {
res *= 2;
}
System.out.println(res);
会产生:
0
本案例讨论如下: 整数溢出产生零。
如果溢出,则返回最小值并从那里继续。如果它溢出,它回到最大值,并从那里继续。
您可以事先检查如下:
public static boolean willAdditionOverflow(int left, int right) {
if (right < 0 && right != Integer.MIN_VALUE) {
return willSubtractionOverflow(left, -right);
} else {
return (~(left ^ right) & (left ^ (left + right))) < 0;
}
}
public static boolean willSubtractionOverflow(int left, int right) {
if (right < 0) {
return willAdditionOverflow(left, -right);
} else {
return ((left ^ right) & (left ^ (left - right))) < 0;
}
}
(你可以用long替换int来对long执行相同的检查)
如果您认为这种情况可能经常发生,那么可以考虑使用可以存储较大值的数据类型或对象,例如long或java.math.BigInteger。最后一个不会溢出,实际上,可用的JVM内存是限制。
如果您碰巧已经使用了Java8,那么您可以使用新的Math#addExact()和Math#subtractExact()方法,它们将在溢出时抛出一个ArithmeticException。
public static boolean willAdditionOverflow(int left, int right) {
try {
Math.addExact(left, right);
return false;
} catch (ArithmeticException e) {
return true;
}
}
public static boolean willSubtractionOverflow(int left, int right) {
try {
Math.subtractExact(left, right);
return false;
} catch (ArithmeticException e) {
return true;
}
}
源代码可以分别在这里和这里找到。
当然,您也可以立即使用它们,而不是将它们隐藏在布尔实用程序方法中。
它环绕着。
e.g:
public class Test {
public static void main(String[] args) {
int i = Integer.MAX_VALUE;
int j = Integer.MIN_VALUE;
System.out.println(i+1);
System.out.println(j-1);
}
}
打印
-2147483648
2147483647
从java8开始,java.lang.Math包就有了addExact()和multiplyExact()这样的方法,它们会在发生溢出时抛出一个ArithmeticException。