次のコードブロックでは、出力が0になります。
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);
}
}
誰かがこれがなぜ起こるのか説明できますか?
プログラムが各ステップで行うことは次のとおりです。
1 * 10 = 10
10 * 11 = 110
110 * 12 = 1320
1320 * 13 = 17160
17160 * 14 = 240240
240240 * 15 = 3603600
3603600 * 16 = 57657600
57657600 * 17 = 980179200
980179200 * 18 = 463356416
463356416 * 19 = 213837312
213837312 * 20 = -18221056
-18221056 * 21 = -382642176
-382642176 * 22 = 171806720
171806720 * 23 = -343412736
-343412736 * 24 = 348028928
348028928 * 25 = 110788608
110788608 * 26 = -1414463488
-1414463488 * 27 = 464191488
464191488 * 28 = 112459776
112459776 * 29 = -1033633792
-1033633792 * 30 = -944242688
-944242688 * 31 = 793247744
793247744 * 32 = -385875968
-385875968 * 33 = 150994944
150994944 * 34 = 838860800
838860800 * 35 = -704643072
-704643072 * 36 = 402653184
402653184 * 37 = 2013265920
2013265920 * 38 = -805306368
-805306368 * 39 = -1342177280
-1342177280 * 40 = -2147483648
-2147483648 * 41 = -2147483648
-2147483648 * 42 = 0
0 * 43 = 0
0 * 44 = 0
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
0 * 97 = 0
0 * 98 = 0
一部のステップでは、乗算の結果、より小さい数値(980179200 * 18 = 463356416)または不正な符号(213837312 * 20 = -18221056)が発生し、整数オーバーフローがあったことに注意してください。しかし、ゼロはどこから来るのでしょうか?読む。
int
データ型 2ビット符号付き 、 2の補数 整数であることに留意して、各ステップの説明を次に示します。
Operation Result(1) Binary Representation(2) Result(3)
---------------- ------------ ----------------------------------------------------------------- ------------
1 * 10 10 1010 10
10 * 11 110 1101110 110
110 * 12 1320 10100101000 1320
1320 * 13 17160 100001100001000 17160
17160 * 14 240240 111010101001110000 240240
240240 * 15 3603600 1101101111110010010000 3603600
3603600 * 16 57657600 11011011111100100100000000 57657600
57657600 * 17 980179200 111010011011000101100100000000 980179200
980179200 * 18 17643225600 100 00011011100111100100001000000000 463356416
463356416 * 19 8803771904 10 00001100101111101110011000000000 213837312
213837312 * 20 4276746240 11111110111010011111100000000000 -18221056
-18221056 * 21 -382642176 11111111111111111111111111111111 11101001001100010101100000000000 -382642176
-382642176 * 22 -8418127872 11111111111111111111111111111110 00001010001111011001000000000000 171806720
171806720 * 23 3951554560 11101011100001111111000000000000 -343412736
-343412736 * 24 -8241905664 11111111111111111111111111111110 00010100101111101000000000000000 348028928
348028928 * 25 8700723200 10 00000110100110101000000000000000 110788608
110788608 * 26 2880503808 10101011101100010000000000000000 -1414463488
-1414463488 * 27 -38190514176 11111111111111111111111111110111 00011011101010110000000000000000 464191488
464191488 * 28 12997361664 11 00000110101101000000000000000000 112459776
112459776 * 29 3261333504 11000010011001000000000000000000 -1033633792
-1033633792 * 30 -31009013760 11111111111111111111111111111000 11000111101110000000000000000000 -944242688
-944242688 * 31 -29271523328 11111111111111111111111111111001 00101111010010000000000000000000 793247744
793247744 * 32 25383927808 101 11101001000000000000000000000000 -385875968
-385875968 * 33 -12733906944 11111111111111111111111111111101 00001001000000000000000000000000 150994944
150994944 * 34 5133828096 1 00110010000000000000000000000000 838860800
838860800 * 35 29360128000 110 11010110000000000000000000000000 -704643072
-704643072 * 36 -25367150592 11111111111111111111111111111010 00011000000000000000000000000000 402653184
402653184 * 37 14898167808 11 01111000000000000000000000000000 2013265920
2013265920 * 38 76504104960 10001 11010000000000000000000000000000 -805306368
-805306368 * 39 -31406948352 11111111111111111111111111111000 10110000000000000000000000000000 -1342177280
-1342177280 * 40 -53687091200 11111111111111111111111111110011 10000000000000000000000000000000 -2147483648
-2147483648 * 41 -88046829568 11111111111111111111111111101011 10000000000000000000000000000000 -2147483648
-2147483648 * 42 -90194313216 11111111111111111111111111101011 00000000000000000000000000000000 0
0 * 43 0 0 0
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
0 * 98 0 0 0
数値に偶数を掛けることがわかっています。
したがって、基本的にプログラムは偶数と別の数値を繰り返し乗算し、右から始まる結果ビットをゼロにします。
PS:乗算に奇数のみが関係する場合、結果はゼロになりません。
コンピューターの乗算は実際には2 ^ 32を法として行われています。被乗数に十分な2の累乗を蓄積すると、すべての値は0になります。
ここには、シリーズのすべての偶数と、その数値を分割する2の最大累乗、および2の累積累乗があります。
num max2 total
10 2 1
12 4 3
14 2 4
16 16 8
18 2 9
20 4 11
22 2 12
24 8 15
26 2 16
28 4 18
30 2 19
32 32 24
34 2 25
36 4 27
38 2 28
40 8 31
42 2 32
42までの積はx * 2 ^ 32 = 0(mod 2 ^ 32)に等しくなります。 2のべき乗のシーケンスは(特に)グレイコードに関連しており、 https://oeis.org/A001511 のように表示されます。
編集:この質問に対する他の応答が不完全である理由を確認するには、奇数の整数に制限された同じプログラムがnot0に収束するという事実を考慮してください、すべてのオーバーフローにもかかわらず。
整数オーバーフロー のように見えます。
これを見てください
BigDecimal product=new BigDecimal(1);
for(int i=10;i<99;i++){
product=product.multiply(new BigDecimal(i));
}
System.out.println(product);
出力:
25977982938941930515945176761070443325092850981258133993315252362474391176210383043658995147728530422794328291965962468114563072000000000000000000000
出力はint
値ではなくなりました。次に、オーバーフローのために間違った値を取得します。
オーバーフローした場合、最小値に戻り、そこから継続します。アンダーフローすると、最大値に戻り、そこから継続します。
もっと info
編集。
コードを次のように変更しましょう
int product = 1;
for (int i = 10; i < 99; i++) {
product *= i;
System.out.println(product);
}
出力:
10
110
1320
17160
240240
3603600
57657600
980179200
463356416
213837312
-18221056
-382642176
171806720
-343412736
348028928
110788608
-1414463488
464191488
112459776
-1033633792
-944242688
793247744
-385875968
150994944
838860800
-704643072
402653184
2013265920
-805306368
-1342177280
-2147483648
-2147483648>>>binary representation is 11111111111111111111111111101011 10000000000000000000000000000000
0 >>> here binary representation will become 11111111111111111111111111101011 00000000000000000000000000000000
----
0
整数オーバーフローのためです。多数の偶数を一緒に乗算すると、2進数の末尾に多数のゼロが付きます。 int
の末尾にゼロが32個以上ある場合、0
にロールオーバーします。
これを視覚化するために、オーバーフローしない数値型で計算された16進数の乗算を以下に示します。末尾のゼロがゆっくりと成長する様子を確認し、int
が最後の8桁の16進数で構成されていることに注意してください。 42(0x2A)を掛けると、int
の32ビットはすべてゼロになります!
1 (int: 00000001) * 0A =
A (int: 0000000A) * 0B =
6E (int: 0000006E) * 0C =
528 (int: 00000528) * 0D =
4308 (int: 00004308) * 0E =
3AA70 (int: 0003AA70) * 0F =
36FC90 (int: 0036FC90) * 10 =
36FC900 (int: 036FC900) * 11 =
3A6C5900 (int: 3A6C5900) * 12 =
41B9E4200 (int: 1B9E4200) * 13 =
4E0CBEE600 (int: 0CBEE600) * 14 =
618FEE9F800 (int: FEE9F800) * 15 =
800CE9315800 (int: E9315800) * 16 =
B011C0A3D9000 (int: 0A3D9000) * 17 =
FD1984EB87F000 (int: EB87F000) * 18 =
17BA647614BE8000 (int: 14BE8000) * 19 =
25133CF88069A8000 (int: 069A8000) * 1A =
3C3F4313D0ABB10000 (int: ABB10000) * 1B =
65AAC1317021BAB0000 (int: 1BAB0000) * 1C =
B1EAD216843B06B40000 (int: 06B40000) * 1D =
142799CC8CFAAFC2640000 (int: C2640000) * 1E =
25CA405F8856098C7B80000 (int: C7B80000) * 1F =
4937DCB91826B2802F480000 (int: 2F480000) * 20 =
926FB972304D65005E9000000 (int: E9000000) * 21 =
12E066E7B839FA050C309000000 (int: 09000000) * 22 =
281CDAAC677B334AB9E732000000 (int: 32000000) * 23 =
57BF1E59225D803376A9BD6000000 (int: D6000000) * 24 =
C56E04488D526073CAFDEA18000000 (int: 18000000) * 25 =
1C88E69E7C6CE7F0BC56B2D578000000 (int: 78000000) * 26 =
43C523B86782A6DBBF4DE8BAFD0000000 (int: D0000000) * 27 =
A53087117C4E76B7A24DE747C8B0000000 (int: B0000000) * 28 =
19CF951ABB6C428CB15C2C23375B80000000 (int: 80000000) * 29 =
4223EE1480456A88867C311A3DDA780000000 (int: 80000000) * 2A =
AD9E50F5D0B637A6610600E4E25D7B00000000 (int: 00000000)
途中のどこかで、製品として0
を取得します。したがって、製品全体が0になります。
あなたの場合:
for (int i = 10; i < 99; i++) {
if (product < Integer.MAX_VALUE)
System.out.println(product);
product *= i;
}
// System.out.println(product);
System.out.println(-2147483648 * EvenValueOfi); // --> this is the culprit (Credits : Kocko's answer )
O/P :
1
10
110
1320
17160
240240
3603600
57657600
980179200
463356416
213837312
-18221056
-382642176
171806720
-343412736
348028928
110788608
-1414463488
464191488
112459776
-1033633792
-944242688
793247744
-385875968
150994944
838860800
-704643072
402653184
2013265920
-805306368
-1342177280 --> Multiplying this and the current value of `i` will also give -2147483648 (INT overflow)
-2147483648 --> Multiplying this and the current value of `i` will also give -2147483648 (INT overflow)
-2147483648 -> Multiplying this and the current value of 'i' will give 0 (INT overflow)
0
0
0
i
の現在の値に数値を掛けるたびに、出力として0
を取得します。
既存の回答の多くはJavaの実装の詳細とデバッグ出力を指しているため、バイナリ乗算の背後にある数学を見て理由を実際に答えてみましょう。
@kasperdのコメントは正しい方向に向かっています。数値を直接乗算せず、代わりにその数値の素因数を乗算するとします。多くの数字よりも2が素因数になります。バイナリでは、これは左シフトに等しくなります。可換性により、最初に2の素因数で乗算できます。つまり、左シフトを行うだけです。
2進乗算規則を見ると、1が特定の桁位置になるのは、両方のオペランド値が1の場合だけです。
したがって、左シフトの効果は、結果をさらに乗算するときの1の最下位ビット位置が増加することです。
整数には最下位ビットのみが含まれるため、結果に十分な頻度で素因数2が含まれている場合、それらはすべて0に設定されます。
乗算結果の符号は結果の数とは独立して計算できるため、この分析では2の補数表現は重要ではないことに注意してください。つまり、値がオーバーフローして負になった場合、最下位ビットは1として表されますが、乗算中は再び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
980179200 * 18 = 463356416 <- Integer Overflow (17643225600)
463356416 * 19 = 213837312
213837312 * 20 = -18221056
-18221056 * 21 = -382642176
-382642176 * 22 = 171806720
171806720 * 23 = -343412736
-343412736 * 24 = 348028928
348028928 * 25 = 110788608
110788608 * 26 = -1414463488
-1414463488 * 27 = 464191488
464191488 * 28 = 112459776
112459776 * 29 = -1033633792
-1033633792 * 30 = -944242688
-944242688 * 31 = 793247744
793247744 * 32 = -385875968
-385875968 * 33 = 150994944
150994944 * 34 = 838860800
838860800 * 35 = -704643072
-704643072 * 36 = 402653184
402653184 * 37 = 2013265920
2013265920 * 38 = -805306368
-805306368 * 39 = -1342177280
-1342177280 * 40 = -2147483648
-2147483648 * 41 = -2147483648
-2147483648 * 42 = 0 <- produce 0
0 * 43 = 0
整数オーバーフローの原因-
980179200 * 18 = 463356416 (should be 17643225600)
17643225600 : 10000011011100111100100001000000000 <-Actual
MAX_Integer : 1111111111111111111111111111111
463356416 : 0011011100111100100001000000000 <- 32 bit Integer
0の原因を生成する-
-2147483648 * 42 = 0 (should be -90194313216)
-90194313216: 1010100000000000000000000000000000000 <- Actual
MAX_Integer : 1111111111111111111111111111111
0 : 00000000000000000000000000000000 <- 32 bit Integer
最終的に、計算はオーバーフローし、最終的にそのオーバーフローはゼロの積になります。 product == -2147483648
およびi == 42
の場合に発生します。このコードを試して、自分で検証してください(または、コードを実行してください here ):
import Java.math.BigInteger;
class Ideone {
public static void main (String[] args) throws Java.lang.Exception {
System.out.println("Result: " + (-2147483648 * 42));
}
}
ゼロになると、もちろんゼロのままになります。より正確な結果を生成するコードを次に示します(コードを実行できます here )。
import Java.math.BigInteger;
class Ideone {
public static void main (String[] args) throws Java.lang.Exception {
BigInteger p = BigInteger.valueOf(1);
BigInteger start = BigInteger.valueOf(10);
BigInteger end = BigInteger.valueOf(99);
for(BigInteger i = start; i.compareTo(end) < 0; i = i.add(BigInteger.ONE)){
p = p.multiply(i);
System.out.println("p: " + p);
}
System.out.println("\nProduct: " + p);
}
}
これは整数オーバーフローです。
Intデータ型は4バイト、または32ビットです。したがって、2 ^(32-1)-1(2,147,483,647)より大きい数値は、このデータ型に格納できません。数値は正しくありません。
非常に大きな数の場合、クラスJava.math.BigInteger:
をインポートして使用する必要があります。
BigInteger product = BigInteger.ONE;
for (long i = 10; i < 99; i++)
product = product.multiply(BigInteger.valueOf(i));
System.out.println(product.toString());
注:intデータ型にはまだ大きすぎるが、8バイト(2 ^(64-1)-1以下の絶対値)に収まるほど小さい数値の場合は、おそらくlong
プリミティブを使用する必要があります。 。
HackerRankの練習問題(www.hackerrank.com)、たとえばアルゴリズム練習セクション、( https://www.hackerrank.com/domains/algorithms/warmup )には、非常に良い多数の質問が含まれています使用する適切なデータ型をどのように考えるかについての良いプラクティスを提供します。