2015-01-13 36 views
1

我正在爲Cay S. Horstmann編寫的書籍「真正不耐煩的Java SE 8」進行練習。之一的基於Number類的改進的練習問:Java 8無符號整數加法和潛在溢出

編寫一個程序,加,減,除,以及0和2 之間進行比較的數字 - 1,使用int值和無符號 操作。說明爲什麼divideUnsignedremainderUnsigned是 必要的。

問題是,如果您添加2個無符號整數,總和可能溢出整數限制。我沒有看到一種方法來避免這種情況,而不用長時間存儲總和並檢查它是否大於Integer.MAX_VALUE。是否有可能只使用ints來做到這一點?

回答

3

用於整數值的Two's complement具有整潔的屬性,對於添加和減去它是無關緊要的,無論您將值解釋爲有符號還是無符號。

因此,即使在CPU級別,也沒有用於添加/減少帶符號或無符號數字的獨特指令。這完全是關於解釋。

因此,當使用帶符號的int類型添加或減去兩個無符號數字時,結果可能會在簽名的int範圍內溢出。但是,使用Integer.toUnsignedString打印當前爲負的數字時,結果將是正確的無符號值,假定該操作甚至在無符號整數值範圍內甚至沒有溢出。

這就是爲什麼類java.lang.Integer只在必要時提供了特殊的無符號的操作,即用於比較兩個無符號值,除法和餘數,並從和String(和long轉換,而A型投從longint是已經足夠用於其他方向)。

+0

感謝您的回覆。我不確定問題是否僅限於打印。如果溢出值被返回並在其他操作中使用,則會出錯。在Java 8中引入的「確切」操作[intValueExact](http://docs.oracle.com/javase/8/docs/api/java/math/BigInteger.html#intValueExact--)將異常這種情況。 –

+1

由於練習要求使用'int'進行計算,因此無法繞過它。當然,你可以用安全的方式定義計算的API,也就是說你可以使用['Integer.toUnsignedLong'](http://docs.oracle.com/javase/8/docs/api/java/lang/ Integer.html#toUnsignedLong-int-)以不能被誤解的形式返回值(使用int計算)。當然,如果你使用['toUnsignedString']返回結果作爲'String',那麼同樣的結果會持續(http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#toUnsignedString -int-)「計算」'!='「返回類型」 – Holger

+0

我希望除此之外還有更多。如果你讀到這個問題,它說「使用int值和未簽名的操作」。如果看起來不是微不足道的,可以創建一個使用'+'運算符添加2個整數的方法。除非我們錯過了一些東西,否則練習不會增加任何價值。 –

1

爲了獲得一個無符號整數,你需要使用Integer.parseUnsignedInt()函數或做一個手動計算。請記住,Java實際上並不具有無符號整數,Java8只是提供了將int作爲無符號對待的能力,以便允許更大範圍的正數值。

按照Java 8 Doc for the Integer class

的無符號整數映射通常與負 編號,以正數比MAX_VALUE較大相關聯的值

所以一個無符號的int和一個簽署一個之間的轉換如果數字大於或等於零且小於或等於Integer.MAX_VALUE,則它保持不變。如果它大於Integer.MAX_VALUE但仍在無符號範圍內,那麼要將其存儲在int中,則需要將2^31添加到它,由於添加溢出被定義爲的方式將其轉換爲正確的值一個手術。除了像int這樣的二進制基元外,溢出和下溢只會導致計數器復位並繼續計數。

int min = Integer.MIN_VALUE;   // -2147483648 
int max = Integer.MAX_VALUE;   // 2147483647 
int overByOne = Integer.MAX_VALUE + 1; // -2147483648 : same as Integer.MIN_VALUE 
int underByOne = Integer.MIN_VALUE - 1; // 2147483647 : same as Integer.MAX_VALUE 

他們行使只是要求你看看Integer類和測試出無符號運算的各種(新中Java8)方法。 Java沒有無符號整數原語,但爲了Integer類中的某些新方法的目的,可以將int值視爲無符號。