sourcecode

왜 자바에서는 10부터 99까지의 모든 숫자의 곱이 0이라고 생각할까요?

copyscript 2023. 1. 30. 22:15
반응형

왜 자바에서는 10부터 99까지의 모든 숫자의 곱이 0이라고 생각할까요?

다음 코드 블록은 출력을 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)가 나타납니다.하지만 0은 어디서 오는 걸까요?읽어주세요.

keeping keeping keeping ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」intdata type은 32비트 부호, 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
  1. 올바른 결과입니다.
  2. 결과의 내부 표현입니다(64비트가 그림에 사용됨).
  3. 하위 32비트를 2가 보완한 결과입니다.

숫자에 짝수를 곱하면 다음과 같이 됩니다.

  • 비트를 왼쪽으로 옮기고 0비트를 오른쪽으로 더합니다.
  • 짝수가 되다

따라서 기본적으로 프로그램은 짝수와 다른 숫자를 반복적으로 곱하여 결과 비트를 오른쪽부터 0으로 만듭니다.

PS: 곱셈에 홀수만 포함되어 있다면 결과는 0이 되지 않습니다.

컴퓨터 곱셈은 실제로 모듈로 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 로 표시됩니다.

편집: 이 질문에 대한 다른 응답이 불완전한 이유를 확인하려면 홀수 정수로만 제한되는 동일한 프로그램이 오버플로우에도 불구하고 0으로 수렴되지 않는다는 사실을 고려하십시오.

정수 오버플로처럼 보입니다.

이것 좀 봐.

BigDecimal product=new BigDecimal(1);
for(int i=10;i<99;i++){
    product=product.multiply(new BigDecimal(i));
}
System.out.println(product);

출력:

25977982938941930515945176761070443325092850981258133993315252362474391176210383043658995147728530422794328291965962468114563072000000000000000000000

은 더 "A"가 .int 수 . 그러면 오버플로우 때문에 값이 잘못 나옵니다.

오버플로우가 발생하면 최소값으로 돌아가 거기서부터 계속됩니다.언더플로우가 발생하면 최대값으로 되돌아가 거기에서 계속됩니다.

상세 정보

편집.

코드를 다음과 같이 변경합니다.

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진수에는 많은 말미에 0이 붙습니다." " " 32 " " " " " " 0 " " " 에 대해 를 int에 롤오버합니다.0.

이를 시각화할 수 있도록 오버플로하지 않는 숫자 유형에 대해 계산된 16진수 단위의 곱셈을 보여 줍니다.서서히 되는 것을 하고, 「0」의 「0」의 「0」의 「0」의 「0」의 「0」의 「0」의 「0」의 「0」의 「0」의 「0」의 「0」의 「0」의 「0」의 「0」에 주의해 주세요.int8시 16분(0x2A)의 모든 가 32비트입니다.int이!!

                                     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)

쯤에서 알 수 00이 .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

i0출력으로 사용합니다.

기존 답변의 대부분은 Java의 구현 세부사항과 디버깅 출력을 가리키므로 이진 곱셈의 이면에 있는 계산을 통해 그 이유를 알아보겠습니다.

@kasperd의 코멘트는 올바른 방향으로 진행됩니다.숫자와 직접 곱하는 것이 아니라 해당 숫자의 소수 요인을 대신 곱한다고 가정합니다.많은 숫자들이 2를 소인수로 가질 것이다.이진법에서 이것은 왼쪽 시프트와 같습니다.교환율에 의해 우리는 먼저 2의 소인수를 곱할 수 있다.그건 그냥 좌회전만 하면 된다는 뜻이죠.

이진수 곱셈 규칙을 살펴볼 때, 1이 특정 자리 위치를 얻는 유일한 경우는 두 피연산자 값이 모두 1인 경우입니다.

따라서 왼쪽 시프트의 효과는 결과를 더 곱할 때 1의 가장 낮은 비트 위치가 증가하는 것입니다.

정수에는 최하위 비트만 포함되므로 결과에서 소인수 2가 충분히 자주 결합되면 모두 0으로 설정됩니다.

곱셈 결과의 부호는 결과 숫자와 독립적으로 계산될 수 있기 때문에 두 개의 보완 표현은 이 분석에는 관심이 없다.즉, 값이 오버플로하여 음수가 되면 최하위 비트가 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

결국 계산은 오버플로우하고 그 오버플로우는 0의 곱으로 이어집니다.이것은, 다음의 경우에 발생합니다.product == -2147483648그리고.i == 42이 코드를 직접 테스트하여 확인합니다(또는 여기서 코드를 실행합니다).

import java.math.BigInteger;

class Ideone {
    public static void main (String[] args) throws java.lang.Exception {
        System.out.println("Result: " + (-2147483648 * 42));
    }
}

일단 0이 되면 당연히 0이 됩니다.다음은 보다 정확한 결과를 얻을 수 있는 코드입니다(여기서 코드를 실행할 수 있습니다).

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)에는 적절한 데이터 유형에 대해 생각하는 방법에 대한 좋은 연습 방법을 제공하는 매우 좋은 대규모 질문이 포함되어 있습니다.

언급URL : https://stackoverflow.com/questions/26375932/why-does-java-think-that-the-product-of-all-numbers-from-10-to-99-is-0

반응형