2012-01-29 105 views
9

更大。如果我有一個分配龍+長不超過Long.MAX_VALUE

Long c = a + b; 

有沒有一種簡單的方法來檢查a + b並不是越大/比Long.MAX_VALUE/Long.MIN_VALUE小?

+0

請參閱問題文本框右側的**如何格式**框以及它上方的** [?] **鏈接(以及其下方的預覽)正確設置問題的格式。 – 2012-01-29 22:18:56

+0

在彙編,將有可能檢查* *攜帶國旗? – 2012-01-29 22:22:08

+0

我刪除了[功課]標籤,作爲OP的評論跟帖,這是隻有在那裏偶然提及。 – 2012-01-29 23:01:01

回答

17

使用Guava,它是那樣簡單

long c = LongMath.checkedAdd(a, b); // throws an ArithmeticException on overflow 

是,我想認爲,可讀性很強確實如此。 (LongMath Javadoc here。)

爲了公平起見,我會提到Apache Commons提供了ArithmeticUtils.addAndCheck(long, long)

如果你想知道他們是如何工作的,那麼,答案是位兩輪牛車爲番石榴的一行:結果不會溢出,如果(a^b) < 0 | (a^(a + b)) >= 0。這是基於技巧,兩個數字的按位異或是非負當且僅當它們具有相同的符號。

所以(a^b) < 0是真的如果ab有不同的跡象,如果是這樣的話,它永遠不會溢出。或者,如果(a^(a + b)) >= 0,則a + b具有相同的符號爲a,所以也沒溢出,變爲負值。

(有關更多的技巧是這樣,調查可愛的書Hacker's Delight

Apache使用基礎上的ab符號更復雜的個案。

+0

+1番石榴。即使比較(如我最初所建議的)可能有效(儘管我太困了,不能正確地考慮它),但願意使用即用功能 – Bozho 2012-01-29 22:28:29

+0

完全披露:我是「LongMath」的作者,其餘的番石榴的common.math包...但@Bozho是正確的,它通常更好地依賴庫代碼而不是滾動自己的實現。(特別是,這個代碼已經經過測試*非常詳盡,所以你不必!) – 2012-01-29 22:32:33

+0

非常酷。添加另一個完整的庫可能會導致這樣一個簡單的情況(檢測溢出在這種情況下是微不足道的),但如果你已經*使用番石榴... – 2012-01-29 22:34:32

0

一種選擇是使用BigInteger類做精確的計算,然後檢查結果是否比有問題的值大於或更小。例如:

if (BigInteger.valueOf(a).add(BigInteger.valueOf(b)).compareTo(BigInteger.valueOf(Long.MAX_VALUE) > 1) { 
    /* Overflow occurred. */ 
} else { 
    /* No overflow occurred. 
} 

希望這有助於!

+0

如果你打算繼續使用全功能'BigInteger',你可以檢查'myBigInt.bitLength() 2012-01-29 22:26:30

+0

@LouisWasserman正確,因爲小於,否則它會被一個關閉。我不認爲這兩個選項中的任何一個都是可讀的,並且其中一個答案只需要Long.MAX_VALUE,而不是Long.MIN_VALUE ... – 2012-01-29 22:42:24

+0

一致認爲這比它的可讀性差。作爲參考,雖然我會說BigInteger方法是檢查* multiplication *溢出的最可讀方法,如果您不願意使用庫。 – 2012-01-29 22:44:29

0

簡約路線:

if(a/2+b/2+(a&b&1)>long.MAX_VALUE/2||a/2+b/2<long.MIN_VALUE/2)... 

你只需要希望它不會優化(a+b)/2

+0

我不相信這是正確的。取a = Long.MAX_VALUE和b = 1。然後,如果添加兩個值,那麼顯然會發生溢出,但是如果將它們減半,a/2 = Long.MAX_VALUE/2和b/2 = 0,那麼a/2 + b/2 <= Long.MAX_VALUE。 – templatetypedef 2012-01-29 22:38:24

+0

@templatetypedef我修復了這個小技巧(增加了溢出) – 2012-01-29 23:20:04

13

這只是一個問題,如果它們具有相同的符號(和都!0)因爲否則你是安全的溢出。如果發生溢出,結果的符號將會翻轉。所以:

long r = a + b; 
if ((a < 0 && b < 0 && r >= 0) || 
    (a > 0 && b > 0 && r <= 0)) { 
    // Overflow occurred 
} 
+2

註冊了,最簡單,最易讀和最好的方法。希望該課程不會採用更「優化」的數學方法。 – 2012-01-29 22:38:32

+0

@owlstead,如果編譯器足夠聰明,它可以使用CPU「攜帶」標誌,所以解決方案就夠用了。當天返回的唯一算法是通過進位完成的。 – bestsss 2012-01-29 22:42:54

+1

Upvoted爲最適合家庭作業的解決方案。 – 2012-01-29 22:50:32