用于算术运算的溢出和范围检查

问题描述:

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

说,上界为短Java是32767,我乘328 * 100,因为乘法答案会已经飞越和答案将是-32736这肯定是小于Short.MAX_VALUE

后,我无法真正做到比较 Short.MAX_VALUE

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

This Short and int只是一个例子。以更大的洞察力思考这个问题,究竟可以为所有数据类型做些什么。

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

+0

你想要警告吗?你想让溢出的数字饱和吗?你想让它停止执行吗?尝试{} catch(integeroverflow){}应该会有帮助 – 2012-08-04 11:17:30

+0

@tuğrulbüyükışıktry-catch在这里没有进入图片,如果抛出异常,那么程序会暂停然后才停止。 – Harshdeep 2012-08-04 11:19:10

+1

没有停止但严重放缓是 – 2012-08-04 11:20:32

有一个计划在Java 8的Math包中包含这样的方法,但我不知道当前的状态是什么。一些源代码可用here。我没有对实现进行多大的测试,但是这可能会给你一些想法。

例如int乘法是利用多头做:

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; 
} 
+1

这看起来有点有趣。谢谢@assylias。我会等待,看看有没有人有更多的建议,我会选择你的答案。 – Harshdeep 2012-08-04 11:35:55

存在用于上溢检查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。

+1

这个问题是关于'预检查输入'。我怎样才能做到这一点。在我实际进行手术之前,我不会知道这一点。所以至少这个建议被排除了。 – Harshdeep 2012-08-04 11:30:12

+0

这取决于您打算执行的操作。我添加了一个加法检查。 – Reimeus 2012-08-04 11:45:00

我会做使用尽可能大的类型计算,的BigInteger/BigDecimal的。然后,我会根据其大小将值分配给适当的类型...有趣的是,有一些有用的方法... 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 
}