これは非常に単純な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ビットの符号付き2の補数型であることを覚えておいてください(翻訳者注:64はjdkでも同じです)。これは、コンピューター内で乗算の各ステップが行うことです。
ラベル(1)は実際の10進数の結果です。
マーク(2)16進および10進法の内部表現結果int型は、データの下位32ビットのみを格納します。
ラベル(3)はラベル(2)の補足です。
0がどこから来るのか知りたい場合は、上記のバイナリ表現の結果を詳しく見てください。注意深い学生は気づくでしょう:
任意の数に偶数を掛けると、偶数になります。
偶数と偶数を乗算すると、全体として2進数が左にシフトし、0は右からスペースを埋めます。
偶数と奇数を乗算しても、右端のゼロの数は変わりません。
乗算が十分に行われると、右側に0ビットが増えます。最後に、積が継続的に42に乗算されると、積のバイナリ表現の下位32ビットはすべて0になるため、intは0になります。
問題の拡張
これで問題の原因がわかったので、別の変数を使用して、バイトを例として、同じ操作を実行できます。
Javaのバイト変数は8ビットの符号付き数値であり、これも1の補数で表されます。上記の結果表から、10から16に連続的に乗算すると、バイナリ結果の下位8ビットがすべて0になるため、このときのバイト変数は0であることがわかります。15に乗算すると、下位8ビットは10010000になります。補数から元のコードを見つける方法を覚えていますか?非常に単純です。符号ビットは変更されず、他のビットは反転されて1が追加され、11110000(-112)になります。興味がある場合は、マシンで結果を確認してください。興味のある学生は、テクニカルディスカッショングループに参加できます:626267345