9

在实际应用之前,我们如何检查算术运算是否会超出数据类型的上限。

说java中的上界简称为32767,我乘以328 * 100,我实际上无法进行比较,Short.MAX_VALUE因为乘法后答案已经溢出并且答案将是-32736,这肯定小于Short.MAX_VALUE

再举一个例子,说我是int在 for 循环中计算 17^10(17 的 10 次方)的值。我怎么知道我的答案在哪个阶段溢出。

Shortint事情只是一个例子。以更大的洞察力来考虑这个问题,对于所有数据类型究竟可以做什么。

我试过谷歌搜索,但没有找到有助于理解这个概念的好链接。

4

3 回答 3

5

溢出检查有 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");
  }
}

BigInteger:将输入转换为 BigInteger 类型的对象,并使用 BigInteger 方法执行所有算术运算。溢出时引发 ArithmeticException。

于 2012-08-04T11:22:40.183 回答
4

有计划在 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;
}

但长乘法使用更复杂的算法:

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;
}  
于 2012-08-04T11:25:25.653 回答
2

我会使用最大的可能类型 BigInteger/BigDecimal 进行计算。然后我会根据它的大小将值分配给适当的类型......有趣的是,有一些有用的方法......如果值不能包含在short中,shortValueExtract将抛出ArithmetricException......

BigDecimal result = BigDecimal.valueOf(328).multiply(
        BigDecimal.valueOf(100));
try {
    short shortResult = result.shortValueExact();
} catch (ArithmeticException e) {
    // overflow
    System.out.println("Overflow!");
}

try {
    int intResult = result.intValueExact();
} catch (ArithmeticException e) {
    // overflow
}
于 2012-08-04T11:36:50.483 回答