2010-08-14 98 views
8

爲什麼下面的代碼打印2147483647,實際值是2147483648?Java的int基本問題

i = (int)Math.pow(2,31) ; 
    System.out.println(i); 

據我所知,最大正值一個int可以支持爲2147483647。那麼,爲什麼這樣的自動代碼換到消極的一面,並打印-2147483648?

i = (int)Math.pow(2,31) +1 ; 
System.out.println(i); 

我是Integer類型的。如果第二個代碼示例(添加兩個整數)可以包裝到負面,如果結果超出正範圍,爲什麼不能包裝第一個樣品? 此外,

i = 2147483648 +1 ; 
System.out.println(i); 

這是非常類似於第二代碼示例拋出編譯錯誤說第一字面超出整數範圍的? 我的問題是,根據第二個代碼示例,爲什麼第一個和第三個樣本不能自動換到另一側?

+0

爲了澄清,這與java.lang.Integer無關,它與int不同。 – polygenelubricants 2010-08-14 11:37:26

+1

這有什麼關係?問題(或問題)將會是相同的,即使我把它轉換爲(Integer)而不是int。 – chedine 2010-08-14 20:16:35

回答

12

對於第一個代碼示例,結果從double縮小到intJLS 5.1.3描述瞭如何縮小轉換爲雙打到整數執行。

相關部分是:

的值必須是過大(大的幅度或 正無窮大的 正值),以及 結果的第一步是最大 表示值鍵入int或 長。

這就是爲什麼2^31(2147483648)減少到Integer.MAX_VALUE(2147483647)。這同樣適用於

i = (int)(Math.pow(2,31)+100.0) ; // addition note the parentheses 

i = (int)10000000000.0d; // == 2147483647 

當添加沒有括號進行,如在你的第二個例子中,我們再與整數加法處理。積分類型使用2's complement來表示值。在此方案下加入1〜

0x7FFFFFFF (2147483647) 

0x80000000 

這是2對-2147483648補充。一些語言爲算術運算執行溢出檢查(例如,Ada將拋出異常)。爪哇,它的C遺產不檢查溢出。算術運算溢出或下溢時,CPU通常會設置一個overflow flag。語言運行時可以檢查這個標誌,雖然這會引入額外的開銷,有些人認爲這是不必要的。

第三個示例沒有編譯,因爲編譯器檢查文字值的類型範圍,並給出超出範圍的編譯器錯誤。請參閱JLS 3.10.1 - Integer Literals

+0

是不是'2147483647 = 0x7FFFFFFF'和'-2147483648 = 0x80000000'? – ILMTitan 2010-08-16 18:06:16

+0

@ILMTitan - 這是正確的,這就是我認爲我寫的,但我看到我寫了別的東西。現在糾正了。 – mdma 2010-08-16 18:44:44

4

那麼爲什麼像這樣的代碼自動包裝到消極的一面,並打印-2147483648?

這被稱爲溢出。 Java是這樣做的,因爲C做到了。 C是因爲大多數處理器都這麼做。在某些語言中,這不會發生。例如,某些語言會拋出一個異常,而在其他語言中,類型會變成能夠保存結果的東西。

我的問題是,根據第二個代碼示例,爲什麼第一個和第三個樣本不能自動換到另一側?

關於第一個程序:Math.pow返回一個double並且不會溢出。當double被轉換爲整數時,它被截斷。

關於你的第三個程序:溢出很少是一個理想的屬性,通常表明你的程序不再工作。如果編譯器可以通過評估一個常量幾乎肯定是代碼中的錯誤,可以看到它發生溢出。如果你想想要一個很大的負數,你爲什麼要寫一個大的正數?