為何從10開始到99連續相乘會得到0?
原文連結 譯者: 李璟([email protected])
這是一塊非常簡單的Java程式碼片段:
public class HelloWorld{ public static void main(String []args){ int product = 1; for (int i = 10; i <= 99; i++) { product *= i; } System.out.println(product); } }
為什麼得出的結果是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,感興趣的朋友請在自己機器上驗證結果。