간단한 프로그램이 있습니다.
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
입니까?
누구든지 이것에 대한 자세한 내용을 알려줄 수 있다면 좋을 것입니다.
변경 int
에 long
그것은 예상대로 번호를 인쇄 할 것으로 보인다. 최대 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
정수 오버플로가 “둘러싸는”이유
답변
아니요, 0 만 인쇄하지 않습니다.
이것을 이것으로 변경하면 무슨 일이 일어나는지 볼 수 있습니다.
int k = 50;
while (true){
i = i + i;
System.out.println(i);
k--;
if (k<0) break;
}
일어나는 일을 오버플로라고합니다.
답변
static int i = 1;
public static void main(String[] args) throws InterruptedException {
while (true){
i = i + i;
System.out.println(i);
Thread.sleep(100);
}
}
넣어 :
2
4
8
16
32
64
...
1073741824
-2147483648
0
0
when sum > Integer.MAX_INT then assign i = 0;
답변
나는 평판이 충분하지 않기 때문에 제어 된 출력으로 동일한 프로그램에 대한 출력 사진을 C로 게시 할 수 없습니다. 직접 시도해보고 실제로 32 번 인쇄 한 다음 오버플로로 인해 설명 된대로 i = 1073741824 + 1073741824
-2147483648으로 변경되고 또 하나의 추가 추가가 int 범위를 벗어 났고 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;
}
답변
의 값은 i
고정 된 양의 이진수를 사용하여 메모리에 저장됩니다. 번호에 사용할 수있는 것보다 더 많은 숫자가 필요한 경우 가장 낮은 숫자 만 저장됩니다 (가장 높은 숫자는 손실 됨).
i
자신을 더하는 것은 i
2 를 곱하는 것과 같습니다 . 10 진수 표기법에서 숫자에 10을 곱하는 것과 마찬가지로 각 숫자를 왼쪽으로 밀고 오른쪽에 0을 두어 수행 할 수 있으며, 이진 표기법으로 숫자에 2를 곱하는 것도 같은 방식으로 수행 할 수 있습니다. 이렇게하면 오른쪽에 한 자리가 추가되므로 왼쪽에서 한 자리가 손실됩니다.
여기에서 시작 값은 1이므로 8 자리 숫자를 사용하여 저장 i
하면
- 0 회 반복 후 값은
00000001
- 1 회 반복 후 값은 다음과 같습니다.
00000010
- 2 회 반복 후 값은
00000100
0이 아닌 마지막 단계까지
- 7 회 반복 후 값은
10000000
- 8 회 반복 후 값은
00000000
숫자를 저장하기 위해 할당 된 이진수 수와 시작 값에 관계없이 결국 모든 숫자가 왼쪽으로 밀려나 가면서 손실됩니다. 그 이후에도 계속해서 숫자를 두 배로 늘려도 숫자는 변경되지 않으며 여전히 모두 0으로 표시됩니다.
답변
정확하지만 31 회 반복 후 1073741824 + 1073741824가 올바르게 계산되지 않고 그 후에는 0 만 인쇄됩니다.
BigInteger를 사용하도록 리팩터링 할 수 있으므로 무한 루프가 올바르게 작동합니다.
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);
}
}
}