2012-08-04 49 views
9

在實際應用它之前,我們如何檢查算術運算是否會超出數據類型的上限。用於算術運算的溢出和範圍檢查

說,上界爲短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

回答

4

有一個計劃在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

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。

+1

這個問題是關於'預檢查輸入'。我怎樣才能做到這一點。在我實際進行手術之前,我不會知道這一點。所以至少這個建議被排除了。 – Harshdeep 2012-08-04 11:30:12

+0

這取決於您打算執行的操作。我添加了一個加法檢查。 – Reimeus 2012-08-04 11:45:00

2

我會做使用盡可能大的類型計算,的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 
}