System.out.println이 사용되지 않는 한 끝없는 루프가 종료됩니다.


91

나는 한 코드의 간단한 비트했다 생각 때문에 무한 루프로 x항상 성장한다 항상보다 큰 남아있을 것이다 j.

int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
   x = x + y;
}
System.out.println(y);

그러나있는 그대로 인쇄 y되고 끝없이 반복되지 않습니다. 이유를 알 수 없습니다. 그러나 다음과 같은 방식으로 코드를 조정할 때 :

int x = 5;
int y = 9;
for (int j = 0; j < x; j++) {
    x = x + y;
    System.out.println(y);
}
System.out.println(y);

끝없는 루프가되고 이유를 모르겠습니다. 자바는 무한 루프를 인식하고 첫 번째 상황에서는 건너 뛰지 만 두 번째 상황에서는 메서드 호출을 실행해야 예상대로 작동합니까? 혼란 스러워요 :)


4
두 번째 루프는 끝이 없습니다. 상한 이 루프 변수보다 빠르게x 증가 하기 때문 입니다. 즉, 상한에 도달하지 않으므로 루프가 "영원히"실행됩니다. 영원히는 아니지만 언젠가는 오버플로가 발생할 가능성이 높습니다. jj
Tim Biegeleisen

75
끝없는 루프가 아닙니다. 첫 번째 경우에 for 루프에서 나오려면 238609294 번의 루프가 필요하고 두 번째로 y238609294 번의 값을 인쇄합니다.
N00b Pr0grammer

13
한 단어 답변 : overflow
qwr

20
재미있게, System.out.println(x)대신의 y말에 문제가 무엇인지를 즉시 보여 것
JollyJoker

9
@TeroLahtinen 아니, 그렇지 않을 것입니다. int 유형이 무엇인지 의심 스러우면 Java 언어 사양을 읽으십시오. 하드웨어 독립적입니다.
9ilsdx 9rvj 0lo

답변:


161

두 예 모두 끝이 없습니다.

문제는 intJava (또는 거의 다른 공통 언어) 의 유형 제한입니다 . 의 값이에 x도달하면 0x7fffffff양수 값을 추가하면 오버플로가 발생 x하고이 음이되어보다 낮아집니다 j.

첫 번째와 두 번째 루프의 차이점은 내부 코드가 훨씬 더 많은 시간이 걸리고 x오버플로 가 발생할 때까지 몇 분 정도 걸릴 수 있다는 것입니다 . 첫 번째 예의 경우 두 번째 미만이 소요되거나 효과가 없기 때문에 최적화 프로그램에 의해 코드가 제거 될 수 있습니다.

토론에서 언급했듯이 시간은 OS가 출력을 버퍼링하는 방법, 터미널 에뮬레이터로 출력하는지 여부 등에 따라 크게 달라 지므로 몇 분보다 훨씬 길 수 있습니다.


48
방금 한 줄을 루프로 인쇄하는 프로그램을 랩톱에서 시도했습니다. 시간을 정했는데 초당 약 1000 줄을 인쇄 할 수있었습니다. 루프가 238609294 번 실행된다는 N00b의 설명에 따르면 루프가 종료되는 데 약 23861 초 (6.6 시간 이상)가 걸립니다. "몇 분"이상입니다.
ajb

11
@ajb : 구현에 따라 다릅니다. println()Windows의 IIRC 는 차단 작업이지만 (일부?) Unix에서는 버퍼링되므로 훨씬 빠릅니다. 또한 사용하려고 print()그것이 돌 때까지, 어떤 버퍼 \n(또는 버퍼 채우기 또는 flush()호출)
BlueRaja - 대니 Pflughoeft

6
또한 출력을 보여주는 터미널에 따라 다릅니다. 극단적 인 예를 보려면 stackoverflow.com/a/21947627/53897 을 참조하십시오 (단어 줄 바꿈으로 인해 속도가 느려지는 경우)
Thorbjørn Ravn Andersen

1
예, UNIX에서 버퍼링되지만 여전히 차단 중입니다. 8K 정도의 버퍼가 채워지면 공간이 생길 때까지 차단됩니다. 속도는 소비되는 속도에 따라 크게 달라집니다. 출력을 / dev / null로 리디렉션하는 것이 가장 빠르지 만 기본값 인 터미널로 보내려면 화면에 그래픽 업데이트가 필요하며 글꼴이 느리게 렌더링되므로 훨씬 더 많은 컴퓨팅 성능이 필요합니다.
penguin359

2
@Zbynek 아, 아마도 그렇 겠지만, 터미널 I / O는 일반적으로 블록이 아닌 라인 버퍼링이 될 것이므로 모든 println은 시스템 호출로 인해 터미널 케이스 속도가 더 느려질 것입니다.
penguin359

33

int로 선언되기 때문에 최대 값에 도달하면 x 값이 음수가되어 루프가 중단됩니다.

그러나 System.out.println이 루프에 추가되면 실행 속도가 표시됩니다 (콘솔에 출력하면 실행 속도가 느려짐). 그러나 두 번째 프로그램 (루프 내부에 syso가있는 프로그램)이 충분히 오래 실행되도록하면 첫 번째 프로그램 (루프 내부에 syso가없는 프로그램)과 동일한 동작을 가져야합니다.


21
사람들은 콘솔에 대한 스팸이 얼마나 많은 코드를 느리게 할 수 있는지 알지 못합니다.
user9993

13

여기에는 두 가지 이유가있을 수 있습니다.

  1. Java는 for루프를 최적화하고 루프 이후를 사용하지 않기 때문에 x단순히 루프를 제거합니다. System.out.println(x);루프 뒤에 문 을 넣어이를 확인할 수 있습니다 .

  2. Java가 실제로 루프를 최적화하지 않고 프로그램을 올바르게 실행하고 있으며 결국 x너무 커져서 int오버플로가 발생할 수 있습니다. 정수 오버플로는 대부분의 경우 정수 x를 j보다 작은 음수로 만들어 루프에서 나와 값을 인쇄합니다 y. System.out.println(x);루프 뒤에 추가하여 확인할 수도 있습니다 .

또한 첫 번째 경우에도 결국 오버플로가 발생하여 두 번째 경우로 렌더링되므로 진정한 무한 루프가되지 않습니다.


14
저는 2 번 문을 선택합니다.
Robby Cornelissen

진실. 음의 척도로 진행되어 루프에서 나왔습니다. 그러나 a sysout는 무한 루프의 환상을 추가하기에는 너무 느립니다.
Pavan Kumar

4
1. 버그 일 것입니다. 컴파일러 최적화는 프로그램의 동작을 변경할 수 없습니다. 이것이 무한 루프 인 경우 컴파일러는 원하는 모든 것을 최적화 할 수 있지만 결과는 여전히 무한 루프 여야합니다. 실제 해결책은 OP가 잘못되었다는 것입니다. 둘 중 어느 것도 무한 루프가 아니며 하나는 다른 것보다 더 많은 작업을 수행하므로 더 오래 걸립니다.
Jörg W Mittag

1
@ JörgWMittag이 경우 x는 다른 것과 관련이없는 지역 변수입니다. 따라서 최적화가 가능합니다. 그러나 이것이 사실인지 판단하기 위해 바이트 코드를 살펴 봐야합니다. 컴파일러가 그런 일을했다고 가정해서는 안됩니다.
HopefullyHelpful

1

둘 다 무한 루프가 아닙니다. 처음에는 j = 0, j <x, j 증가 (j ++), j는 정수이므로 루프가 최대 값에 도달 할 때까지 실행 된 다음 overflow (An Integer Overflow가 조건입니다. 곱하기 나 더하기와 같은 산술 연산의 결과가이를 저장하는 데 사용 된 정수 유형의 최대 크기를 초과 할 때 발생합니다.) 두 번째 예의 경우 시스템은 루프가 중단 될 때까지 y 값을 인쇄합니다.

무한 루프의 예를 찾고 있다면 다음과 같이 보일 것입니다.

int x = 6;

for (int i = 0; x < 10; i++) {
System.out.println("Still Looping");
}

(x)는 결코 10의 값을 얻지 못하기 때문입니다.

이중 for 루프로 무한 루프를 만들 수도 있습니다.

int i ;

  for (i = 0; i <= 10; i++) {
      for (i = 0; i <= 5; i++){
         System.out.println("Repeat");   
      }
 }

첫 번째 for 루프가 i <10이라고 말하고 두 번째 for 루프로 들어가고 두 번째 for 루프가 == 5가 될 때까지 (i)의 값을 증가시키기 때문에이 루프는 무한합니다. 그런 다음 첫 번째 for 루프로 진행합니다. i <10이기 때문에 for 루프 다시, 두 번째 for 루프 후에 재설정되기 때문에 프로세스가 계속 반복됩니다.


1

값이 x초과 되면 2,147,483,647(의 최대 값 int) y를 인쇄하든 인쇄하지 않든 x음수가되고 더 이상 크지 않기 때문에 유한 루프 j입니다.

yto 값을 변경하고 루프에서 100000인쇄 y하면 루프가 곧 중단됩니다.

그것이 무한 해 졌다고 느끼는 이유는 System.out.println(y);아무 동작도하지 않는 것보다 코드가 매우 느리게 실행되도록 만들었 기 때문입니다.


0

흥미로운 문제 실제로 두 경우 모두 루프는 끝이 없습니다

그러나 그들 사이의 주요 차이점은 언제 종료되고 x최대 int값 을 초과 하는 데 걸리는 시간 은 2,147,483,647오버플로 상태에 도달하고 루프가 종료되는 것입니다.

이 문제를 이해하는 가장 좋은 방법은 간단한 예제를 테스트하고 그 결과를 보존하는 것입니다.

:

for(int i = 10; i > 0; i++) {}
System.out.println("finished!");

산출:

finished!
BUILD SUCCESSFUL (total time: 0 seconds)

이 무한 루프를 테스트 한 후 종료하는 데 1 초도 걸리지 않습니다.

for(int i = 10; i > 0; i++) {
    System.out.println("infinite: " + i);
}
System.out.println("finished!");

산출:

infinite: 314572809
infinite: 314572810
infinite: 314572811
.
.
.
infinite: 2147483644
infinite: 2147483645
infinite: 2147483646
infinite: 2147483647
finished!
BUILD SUCCESSFUL (total time: 486 minutes 25 seconds)

이 테스트 케이스에서 프로그램을 종료하고 종료하는 데 걸리는 시간이 크게 다릅니다.

인내하지 않으면이 루프가 끝이없고 종료되지 않을 것이라고 생각할 수 있지만 실제로 종료하고 i값이 있는 오버플로 상태에 도달하는 데 몇 시간이 걸립니다 .

마지막으로 우리는 print 문을 for 루프 안에 넣은 후에 print 문이없는 첫 번째 경우에 루프보다 훨씬 더 많은 시간이 걸릴 것이라는 결론을 내 렸습니다.

프로그램을 실행하는 데 걸리는 시간은 컴퓨터 사양, 특히 처리 능력 (프로세서 용량), 운영 체제 및 프로그램을 컴파일하는 IDE에 따라 다릅니다.

이 사례를 다음에서 테스트합니다.

Lenovo 2.7GHz Intel Core i5

운영체제 : Windows 8.1 64x

IDE : NetBeans 8.2

프로그램을 마치는 데는 약 8 시간 (486 분)이 걸립니다.

또한 for 루프에서 단계가 증가하는 것을 알 수 있습니다. i = i + 1 가 최대 int 값에 도달하는 데 매우 느린 요소임을 알 수 있습니다.

이 요소를 변경하고 더 짧은 시간에 루프를 테스트하기 위해 단계를 더 빠르게 증가시킬 수 있습니다.

우리가 i = i * 10그것을 넣고 테스트한다면 :

for(int i = 10; i > 0; i*=10) {
           System.out.println("infinite: " + i);
}
     System.out.println("finished!");

산출:

infinite: 100000
infinite: 1000000
infinite: 10000000
infinite: 100000000
infinite: 1000000000
infinite: 1410065408
infinite: 1215752192
finished!
BUILD SUCCESSFUL (total time: 0 seconds)

보시다시피 이전 루프에 비해 매우 빠릅니다.

프로그램 실행을 종료하고 완료하는 데 1 초도 걸리지 않습니다.

이 테스트 예제 이후 나는 문제를 명확히하고 Zbynek Vyskovsky-kvr000의 답변의 타당성을 증명해야한다고 생각하며 , 또한이 질문에 대한 답변이 될 것 입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.