program story

왜 나는 = 나는 + 나는 0을 제공합니까?

inputbox 2020. 8. 24. 08:19
반응형

왜 나는 = 나는 + 나는 0을 제공합니까?


간단한 프로그램이 있습니다.

public class Mathz {
    static int i = 1;
    public static void main(String[] args) {    
        while (true){
            i = i + i;
            System.out.println(i);
        }
    }
}

이 프로그램을 실행할 때 내가 보는 것은 출력에 0대한 것 i입니다. 나는 우리가 i = 1 + 1, 그 뒤에 i = 2 + 2, i = 4 + 4등이 뒤따를 것이라고 예상했을 것입니다 .

이것은 우리 i가 왼쪽 에서 다시 선언 시도하자마자 그 값이로 재설정된다는 사실 때문 0입니까?

누구든지 이것에 대한 자세한 내용을 알려줄 수 있다면 좋을 것입니다.

변경 intlong그것은 예상대로 번호를 인쇄 할 것으로 보인다. 최대 32 비트 값에 도달하는 속도에 놀랐습니다!


이 문제는 정수 오버플로 때문입니다.

32 비트 2- 보완 산술 :

i실제로 2의 거듭 제곱 값을 갖는 것으로 시작하지만 2 30에 도달하면 오버플로 동작이 시작됩니다 .

2 30 + 2 30 = -2 31

-2 31 + -2 31 = 0

... int산술에서, 본질적으로 산술 mod 2 ^ 32이기 때문입니다.


소개

문제는 정수 오버플로입니다. 오버플로되면 최소값으로 돌아가서 계속됩니다. 언더 플로하면 최대 값으로 돌아가서 계속됩니다. 아래 이미지는 주행 거리계입니다. 나는 이것을 사용하여 오버플로를 설명합니다. 기계적 오버플로이지만 여전히 좋은 예입니다.

주행 거리계에서 max digit = 9, 그래서 최대 수단을 넘어서는 9 + 1, 이것은 전달하고 제공합니다 0; 그러나으로 변경할 더 높은 숫자가 없으므로 1카운터가로 재설정됩니다 zero. "정수 오버플로"라는 아이디어가 떠 오릅니다.

여기에 이미지 설명 입력 여기에 이미지 설명 입력

int 유형의 가장 큰 10 진수 리터럴은 2147483647 (2 31 -1)입니다. 0에서 2147483647까지의 모든 10 진수 리터럴은 int 리터럴이 나타날 수있는 모든 위치에 나타날 수 있지만 리터럴 2147483648은 단항 부정 연산자-의 피연산자로만 나타날 수 있습니다.

정수 덧셈이 오버플로되면 결과는 충분히 큰 2의 보수 형식으로 표현 된 수학적 합의 하위 비트입니다. 오버플로가 발생하면 결과의 부호가 두 피연산자 값의 수학적 합계 부호와 동일하지 않습니다.

따라서 2147483647 + 1오버플로되어 -2147483648. 따라서과 int i=2147483647 + 1같지 않은 오버플로 될 것 2147483648입니다. 또한 "항상 0을 인쇄합니다"라고 말합니다. http://ideone.com/WHrQIW 이므로 그렇지 않습니다 . 아래에서이 8 개의 숫자는 피벗 및 오버플로 지점을 보여줍니다. 그런 다음 0을 인쇄하기 시작합니다. 또한 계산 속도가 빠르다는 사실에 놀라지 마십시오. 오늘날의 기계는 빠릅니다.

268435456
536870912
1073741824
-2147483648
0
0
0
0

정수 오버플로가 "둘러싸는"이유

원본 PDF


아니요, 0 만 인쇄하지 않습니다.

Change it to this and you will see what happens.

    int k = 50;
    while (true){
        i = i + i;
        System.out.println(i);
        k--;
        if (k<0) break;
    }

What happens is called overflow.


static int i = 1;
    public static void main(String[] args) throws InterruptedException {
        while (true){
            i = i + i;
            System.out.println(i);
            Thread.sleep(100);
        }
    }

out put:

2
4
8
16
32
64
...
1073741824
-2147483648
0
0

when sum > Integer.MAX_INT then assign i = 0;

Since I don't have enough reputation I cannot post the picture of the output for the same program in C with controlled output, u can try yourself and see that it actually prints 32 times and then as explained due to overflow i=1073741824 + 1073741824 changes to -2147483648 and one more further addition is out of range of int and turns to Zero .

#include<stdio.h>
#include<conio.h>

int main()
{
static int i = 1;

    while (true){
        i = i + i;
      printf("\n%d",i);
      _getch();
    }
      return 0;
}

The value of i is stored in memory using a fixed quantity of binary digits. When a number needs more digits than are available, only the lowest digits are stored (the highest digits get lost).

Adding i to itself is the same as multiplying i by two. Just like multiplying a number by ten in decimal notation can be performed by sliding each digit to the left and putting a zero on the right, multiplying a number by two in binary notation can be performed the same way. This adds one digit on the right, so a digit gets lost on the left.

Here the starting value is 1, so if we use 8 digits to store i (for example),

  • after 0 iterations, the value is 00000001
  • after 1 iteration , the value is 00000010
  • after 2 iterations, the value is 00000100

and so on, until the final non-zero step

  • after 7 iterations, the value is 10000000
  • after 8 iterations, the value is 00000000

No matter how many binary digits are allocated to store the number, and no matter what the starting value is, eventually all of the digits will be lost as they are pushed off to the left. After that point, continuing to double the number will not change the number - it will still be represented by all zeroes.


It is correct, but after 31 iterations, 1073741824 + 1073741824 doesn't calculate correctly and after that prints only 0.

You can refactor to use BigInteger, so your infinite loop will work correctly.

public class Mathz {
    static BigInteger i = new BigInteger("1");

    public static void main(String[] args) {    

        while (true){
            i = i.add(i);
            System.out.println(i);
        }
    }
}

For debugging such cases it is good to reduce the number of iterations in the loop. Use this instead of your while(true):

for(int r = 0; r<100; r++)

You can then see that it starts with 2 and is doubling the value until it is causing an overflow.


I'll use an 8-bit number for illustration because it can be completely detailed in a short space. Hex numbers begin with 0x, while binary numbers begin with 0b.

The max value for an 8-bit unsigned integer is 255 (0xFF or 0b11111111). If you add 1, you would typically expect to get: 256 (0x100 or 0b100000000). But since that's too many bits (9), that's over the max, so the first part just gets dropped, leaving you with 0 effectively (0x(1)00 or 0b(1)00000000, but with the 1 dropped).

So when your program runs, you get:

1 = 0x01 = 0b1
2 = 0x02 = 0b10
4 = 0x04 = 0b100
8 = 0x08 = 0b1000
16 = 0x10 = 0b10000
32 = 0x20 = 0b100000
64 = 0x40 = 0b1000000
128 = 0x80 = 0b10000000
256 = 0x00 = 0b00000000 (wraps to 0)
0 + 0 = 0 = 0x00 = 0b00000000
0 + 0 = 0 = 0x00 = 0b00000000
0 + 0 = 0 = 0x00 = 0b00000000
...

유형의 가장 큰 10 진수 리터럴 int2147483648 (= 2 31 )입니다. 0에서 2147483647 까지의 모든 10 진수 리터럴은 int 리터럴이 나타날 수있는 모든 위치에 나타날 수 있지만 리터럴 2147483648 은 단항 부정 연산자-의 피연산자로만 나타날 수 있습니다.

정수 덧셈이 오버플로되면 결과는 충분히 큰 2의 보수 형식으로 표현 된 수학적 합의 하위 비트입니다. 오버플로가 발생하면 결과의 부호가 두 피연산자 값의 수학적 합계 부호와 동일하지 않습니다.

참고 URL : https://stackoverflow.com/questions/24173463/why-does-iii-give-me-0

반응형