나는 어떤 값을 위해 while (i == i + 1) {} 루프를 영원히 수행합니까?


120

나는 영국 대학 시험에서 고급 프로그래밍 과정에서이 퍼즐을 넘었다 .

i가 지금까지 선언되지 않은 다음 루프를 고려하십시오.

while (i == i + 1) {}

while 루프가 영원히 계속되도록i 이 루프 앞에 있는의 정의를 찾으십시오 .

이 코드 스 니펫에 대해 동일한 질문을 던진 다음 질문 :

while (i != i) {}

나에게 분명했다. 물론이 다른 상황에서는 NaN그렇습니다.하지만 저는 이전 상황에 갇혀 있습니다. 이것이 오버플로와 관련이 있습니까? 이러한 루프가 Java에서 영원히 반복되는 원인은 무엇입니까?


3
.equals()메서드 를 재정의 할 가능성이 있습니까? 나는 선언되지 않았으므로 원하는 클래스를 사용할 수 있습니다.
Geno Chen

7
@Raedwald 공부 "비전문적"코드는 그래서 ... 어쨌든, 좋은 질문이야, 당신이 더 많은 "전문가"하게
앤드류 Tobilko

12
이 또한, 값이 널 (NULL) 숫자 유형의 작동 C #에서 재미있는 사실 null때문에, null == null사실, 그리고 null + 1이다 null.
Eric Lippert 2018

4
@EricDuminil : 상황은 당신이 상상하는 것보다 훨씬 더 나쁩니다. 많은 언어에서 부동 소수점 산술에서 수행해야합니다 적어도 그것을에서 할 수있는 수단, 이중에서 지정한 정밀도의 64 비트 고정밀 컴파일러의 변덕, 실천이 문제가 발생합니다 . 0.2 + 0.1 == 0.3컴파일러 설정, 달의 위상 등에 따라 값이 변경되는 이유를 궁금해하는 C # 프로그래머가이 사이트에 대한 12 개의 질문을 지적 할 수 있습니다 .
Eric Lippert 2018

5
@EricDuminil :이 혼란에 대한 책임은 Intel이 인텔에 있습니다. Intel 은 숫자를 등록 할 수 있다면 높은 정밀도와 더 빠른 부동 소수점 연산 을 수행하는 칩셋 을 제공했습니다. 즉, 부동 소수점 계산의 결과가 값에 따라 값이 변경 될 수 있음을 의미합니다. 옵티마이 저의 레지스터 스케줄러가 오늘날 얼마나 잘 작동하는지. 언어 디자이너로서 당신의 선택은 반복 가능한 계산빠르고 정확한 계산 사이 에 있으며, 부동 소수점 수학에 관심이있는 커뮤니티는 후자를 선택할 것입니다.
Eric Lippert 2018

답변:


142

우선, while (i == i + 1) {}루프는의 값을 변경하지 않기 i때문에이 루프를 무한대로 만드는 i것은 만족 하는 값을 선택하는 것과 같습니다 i == i + 1.

다음과 같은 많은 값이 있습니다.

"이국적인"것부터 시작해 보겠습니다.

double i = Double.POSITIVE_INFINITY;

또는

double i =  Double.NEGATIVE_INFINITY;

이러한 값이 만족하는 이유 i == i + 1
JLS 15.18.2에 명시되어 있습니다. 숫자 유형에 대한 더하기 연산자 (+ 및-) :

무한대와 유한 값의 합은 무한 피연산자와 같습니다.

무한 값에 유한 값을 추가하면 무한 값이 생성되므로 이는 놀라운 일이 아닙니다.

즉, i만족 하는 대부분의 값 i == i + 1은 단순히 큰 double(또는 float) 값입니다.

예를 들면 :

double i = Double.MAX_VALUE;

또는

double i = 1000000000000000000.0;

또는

float i = 1000000000000000000.0f;

doublefloat유형은 충분히 큰 걸릴 그렇다면, 제한된 정밀도를 가지고 double또는 float추가 값을 1같은 값 발생합니다 그것.


10
또는 (double)(1L<<53)-또는float i = (float)(1<<24)
dave_thompson_085 nov.

3
@Ruslan : 어떤 수학자도 동의하지 않을 것입니다. 부동 소수점 숫자는 거의 의미가 없습니다. 그들은 비 연관적이고 비 반사적이며 (NaN! = NaN), 대체 할 수도 없습니다 (-0 == 0, 그러나 1/0! = 1 / -0). 따라서 대부분의 대수 기계는 적용 할 수 없습니다.
Kevin

2
@Kevin 부동 소수점 숫자는 실제로 일반적으로 너무 이해하기 어렵지만 무한대의 동작 (해당 문장에 설명되어 있음)은 의미가 있도록 설계되었습니다.
Ruslan

4
@Kevin 부동에 공평하게 말하면, 무한대 나 정의되지 않은 값을 다룰 경우 대수에 나열된 속성을 가정 할 수 없습니다.
Voo

2
@Kevin : IMHO, 부동 소수점 수학이 "양수 및 음수 0"기호 양수, 음수 및 부호없는 "무한"개념을 하나의 "진정한 0"과 함께 대체하면 훨씬 더 의미가있을 수 있습니다. NaN은 자신과 같습니다. True zero는 모든 경우에 가산 적 정체성으로 행동 할 수 있으며, 무한 소수로 나누기를 포함하는 어떤 연산은 무한 소수가 양수라고 가정하는 편향을 잃게됩니다.
supercat

64

이 퍼즐은 Joshua Bloch와 Neal Gafter의 "Java Puzzlers : Traps, Pitfalls, and Corner Cases"책에 자세히 설명되어 있습니다.

double i = Double.POSITIVE_INFINITY;
while (i == i + 1) {}

또는:

double i = 1.0e40;
while (i == i + 1) {}

둘 다 무한 루프가됩니다. 왜냐하면 1충분히 큰 부동 소수점 값을 추가해도 값이 변경되지는 않기 때문입니다. 그 이유는 후속 작업 1과 "격차를 해소"하지 않기 때문 입니다.

두 번째 퍼즐에 대한 참고 사항 (미래 독자 용) :

double i = Double.NaN;
while (i != i) {}

또한 NaN은 자체 2를 포함하여 부동 소수점 값과 같지 않기 때문에 무한 루프 가 발생합니다 .


1-Java Puzzlers : 함정, 함정 및 코너 케이스 (4 장-Loopy Puzzlers).

2- JLS §15.21.1



0

아이디어 : 부울은 어떻습니까?

bool i = TRUE;

이 경우가 i + 1 == i아닌가?


언어에 따라 다릅니다. 많은 언어가 int와 결합 될 때 자동으로 부울을 int로 강제 변환합니다. 다른 사람들은 당신이 제안한대로 int를 부울로 강제합니다.
Carl Witthoft

8
이 질문은 Java 질문이며 귀하의 제안은 Java에서 컴파일을 통과하지 못합니다 ( 및 피연산자로 사용 +하는 연산자 가 없음 ). booleanint
Eran 2018

@Eran : 이것이 연산자 오버로딩의 전체 아이디어입니다. Java 부울이 C ++ 부울처럼 작동하도록 만들 수 있습니다.
Dominique

4
Java가 연산자 오버로딩을 지원하지 않는다는 점을 제외하고는 할 수 없습니다.
CupawnTae
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.