2017-01-01 51 views
-1

考慮下面的代碼片段:爲什麼50000 * 49999等於-1795017296?

public class Test { 
    public static void main(String[] args) {  
     long result = 50000 * 49999; 

     System.out.print(result); 
    } 
} 

我跑這個程序,它產生的-1795017296的輸出,而不是預期的2499950000。有人可以解釋我爲什麼會出現這種情況嗎?

+5

'50000'和'49999'是int文字。試試50000L * 49999; – Eran

+1

**或**,'long result =(long)50000 * 49999;' –

+0

如果您希望獲得更高的值,請參閱java中的BigInteger類。在你的情況下,在50000和49999之前保持一個(長)的工作。 – SmashCode

回答

6

這是因爲你正在處理整數文字,而不是長文字,所以發生整數溢出。數字50,000和49,000乘以第一個,然後產品(一個整數發生溢出)在存入result時被「提升」爲long。

50,000 * 49,999產生2,499,950,000,其高於32位有符號數據類型的整數範圍,從-2,147,483,648到2,147,483,647。

溢出後,它回到最小值並從開始。由於2,499,950,000與2,147,483,648(第一個溢出的數字)之間的差值爲352,466,352(溢出的數量),因此它在繞過(計算溢出結果)時被添加到-2,147,483,648。結果爲-1,795,017,296。


爲了糾正這個問題,嘗試:

long result = 50000L * 49999; 

代替,它使用長字面從而導致較長的產品,以防止溢出,因爲它是64位(與範圍從-9,223,372,036,854,775,808到 9,223,372,036,854,775,807 )。如果一個操作數很長,那麼整個事物在乘法時就被「提升」到很長的距離。

+0

如果我知道它的正確性,它本質上不會 - 將其重置爲最小值,這只是試圖將(不存在的)第33位設置爲1並且取消所有低位的副作用,因爲這是一個例外 - 例如 - 從3到4。我是對的嗎? – Mordechai

+0

@MouseEvent對不起,回覆晚了。之所以這樣做,是因爲有符號整數的最大數字是2,147,483,647,其中二進制是'01111111 11111111 11111111 11111111'。一旦你添加一個,前導0就變成1,這就像你說的那樣,將它們全部否定並變成'10000000 00000000 00000000 00000000',即-2,147,483,648。 – Li357

1

您可以使用此爲避免長期溢出.....投整數:

class Test { 
    public static void main(String[] args) { 
    long result = 50000L*49999; 
    System.out.print(result); 
    } 
} 
+2

此處不需要鑄造。 – Mordechai

+0

我沒有得到,@MouseEvent。你需要確保你乘以'long's,而不是'int's。你毫無疑問意味着一些正確的東西,但它沒有透露給我。 –

+1

你的方法是首先創建一個int,然後強制轉換爲long。看看其他答案,附加一個'L'可以創造一個長處,減少一條額外的指令。 – Mordechai

1

讓我們仔細分析這一步一步

long result = 50000*49999;

首先50000得到並存儲在可由int佔用的空間中。這是因爲所有數字文字都被視爲int,除非後綴爲'L`和喜歡。

49999相同。

此外,該表達式被評估爲50000*49999並且它們被存儲爲整數。

這是發生溢出的地方。 int無法存儲產品產生的值。

此溢出值僅存儲爲long

現在,如果您將任何數字後綴爲L Java將會發現產品/表達式可能導致long並避免溢出。

有人可能會問爲什麼Java不會預期評估可能需要long,因爲變量的類型是long但這是一個不同的問題。

所以你感到驚訝的消極結果是沒有放錯IMO。