在实际应用之前,我们如何检查算术运算是否会超出数据类型的上限.
说java中的shortbound为32767,我乘以328*100,我实际上无法做比较,Short.MAX_VALUE因为乘法后答案已经溢出并且答案是-32736肯定小于Short.MAX_VALUE
再举一个例子,我说int在for循环中计算17 ^ 10(功率10为17)的价值.我怎么知道我的答案在什么阶段溢出.
这Short和int东西只是一个例子.想想这个问题,可以更好地理解为所有数据类型可以做些什么.
我尝试使用谷歌搜索,但没有找到有助于理解这个概念的良好链接.
溢出检查有3种可能的方法:
使用更大的类型并向下转换:将输入转换为下一个更大的原始整数类型,并以更大的大小执行算术运算.检查每个中间结果是否有原始较小类型的溢出; 如果范围检查失败,则抛出ArithmeticException.
预检输入:检查每个算术运算符的输入,以确保不会发生溢出.如果执行操作会溢出,则再次抛出ArithmeticException,否则执行操作.
例如:
static void preAddCheck(int left, int right) throws ArithmeticException {
if (right > 0 ? left > Integer.MAX_VALUE - right : left < Integer.MIN_VALUE - right) {
throw new ArithmeticException("Integer overflow");
}
}
Run Code Online (Sandbox Code Playgroud)
BigInteger:将输入转换为BigInteger类型的对象,并使用BigInteger方法执行所有算术.溢出时抛出ArithmeticException.
有计划在 Java 8 的 Math 包中包含此类方法,但我不知道当前状态如何。一些源代码可以在这里找到。我不知道实施的测试情况如何,但这可以给你一些想法。
例如,int 乘法是通过使用 long 来完成的:
public static int multiplyExact(int x, int y) {
long r = (long)x * (long)y;
if ((int)r != r) {
throw new ArithmeticException("long overflow");
}
return (int)r;
}
Run Code Online (Sandbox Code Playgroud)
但长乘法使用更复杂的算法:
public static long multiplyExact(long x, long y) {
long r = x * y;
long ax = Math.abs(x);
long ay = Math.abs(y);
if (((ax | ay) >>> 31 != 0)) {
// Some bits greater than 2^31 that might cause overflow
// Check the result using the divide operator
// and check for the special case of Long.MIN_VALUE * -1
if (((y != 0) && (r / y != x)) ||
(x == Long.MIN_VALUE && y == -1)) {
throw new ArithmeticException("long overflow");
}
}
return r;
}
Run Code Online (Sandbox Code Playgroud)