閱讀95 返回首頁    go 阿裏雲 go 技術社區[雲棲]


為何從10開始到99連續相乘會得到0?

這是一塊非常簡單的Java代碼片段:

01 public class HelloWorld{
02  
03     public static void main(String []args){
04  
05         int product = 1;
06  
07         for (int i = 10; i <= 99; i++) {
08  
09             product *= i;
10  
11         }
12  
13         System.out.println(product);
14  
15     }
16  
17 }

為什麼得出的結果是0呢?

問題現象

蛋疼的同學可能會發現這個程序執行的規律:
1 * 10 = 10

10 * 11 = 110

110 * 12 = 1320

1320 * 13 = 17160

17160 * 14 = 240240

240240 * 15 = 3603600

3603600 * 16 = 57657600

57657600 * 17 = 980179200

……

 

-1342177280 * 40 = -2147483648

-2147483648 * 41 = -2147483648

-2147483648 * 42 = 0

0 * 43 = 0

0 * 44 = 0

……

0 * 97 = 0

0 * 98 = 0
程序從42開始就已經輸出0,所以42以後的數字相乘的結果就顯而易見了。從結果中發現,乘積的符號已一種難以理解的方式變換著,表明乘積已經溢出了,同時也說明Java並不會理會整數的上下溢出。

問題解答

請記住Java的int類型是32位的有符號二進製補碼表示的數字類型(譯者注:64為jdk同樣如此)。這是每一步乘法在計算機內部所做的操作:

標注(1)是實際十進製結果。

標注(2)十六進製以及十進製的內部表示結果,int類型隻會存儲低32位的數據。

標注(3)是標注(2)的補碼形式。

如果你好奇0從哪裏來,請仔細看上方2進製表示的結果。細心的同學會注意到:

任何一個數與偶數相乘得偶數。

偶數與偶數相乘,會將2進製位整體左移,0從右邊填補空位。

偶數與奇數相乘,不會改變最右方0的數量。

當乘法執行的足夠多次時,右方的0位會越來越多。最終,連續乘到42時,乘積的2進製表示的低32位全是0,所以int將會是0。

問題擴展

既然知道了問題的原因,我們換一種變量來做同樣的操作,以byte為例。

Java的byte變量是8位的有符號數,同樣也是補碼表示。從上方結果表格看出,連續從10乘到16時,2進製結果的低8位全都是0,所以此時的byte變量是0。而連續乘到15時,低8位是10010000,還記得怎麼由補碼求原碼嗎?很簡單, 符號位不變,其餘位取反加1,得出11110000,既-112,感興趣的朋友請在自己機器上驗證結果。

最後更新:2017-05-22 16:37:19

  上一篇:go  軟件事務內存導論(五)創建嵌套事務
  下一篇:go  PHP培訓機構排名