[javascript] 이 ‘for’루프가 중지되고 왜 / 왜 안됩니까? for (var i = 0; 1 / i> 0; i ++) {}

for루프가 멈추나요?

for (var i=0; 1/i > 0; i++) {
}

그렇다면 언제, 왜? 멈춘다 고 들었지만 그럴 이유가 없었습니다.

업데이트

조사의 일환으로 내부에서 일어나는 모든 일을 설명하는 매우 길고 자세한 기사를 작성했습니다. JavaScript의 숫자 유형에 대해 알아야 할 사항은 다음과 같습니다.



답변

(저는 메타 콘텐츠의 팬은 아니지만 : gotnullle_m의 답변은 정확하고 유용합니다. 원래 답변 이었으며이 커뮤니티 위키가 게시 된 후 수정 된 내용 이 훨씬 더 많습니다 .이 CW의 원래 동기는 대부분의 편집의 결과로 사라졌지 만 여전히 유용합니다. 따라서 … 또한, 목록에 작성자가 몇 명 밖에 없지만 많은 다른 커뮤니티 회원들이 주석을 접고 정리하는 데 크게 도움을주었습니다. 이름에서 CW가 아닙니다.)


루프는 올바르게 구현 된 JavaScript 엔진에서 멈추지 않습니다. (엔진의 호스트 환경은 끝이 없기 때문에 결국 종료 될 수 있지만 이는 또 다른 문제입니다.)

그 이유는 다음과 같습니다.

  1. 때 처음 i이며 0, 조건은 1/i > 0자바 스크립트, 때문에 사실 1/0입니다 Infinity, 그리고 Infinity > 0사실이다.

  2. 그 후, i증가하고 오랫동안 양의 정수 값으로 계속 증가합니다 (추가 9,007,199,254,740,991 회 반복). 그 모든 경우에 1/i남아있을 것이다 > 0(비록에 대한 값을 1/i얻을 정말 끝을 향해 작은!) 루프는 루프에 포함까지 계속 그렇게 i값에 도달 Number.MAX_SAFE_INTEGER.

  3. JavaScript의 숫자는 IEEE-754 배정 밀도 이진 부동 소수점으로, 빠른 계산과 광범위한 범위를 제공하는 상당히 컴팩트 한 형식 (64 비트)입니다. 숫자를 부호 비트, 11 비트 지수 및 52 비트 유효 값으로 저장하여이를 수행합니다 (하지만 영리함을 통해 실제로 53 비트의 정밀도를 얻음). 그것은의 바이너리 유효 숫자 (플러스 약간의 영리함은) 우리에게 가치를 제공하고, 지수는 우리에게 숫자의 크기를 제공합니다 (기본 2) 부동 소수점.

    당연히 중요한 비트가 너무 많아서 모든 숫자를 저장할 수있는 것은 아닙니다. 다음은 숫자 1과 형식이 저장할 수있는 1 다음으로 높은 숫자 인 1 + 2 -52 ≈ 1.00000000000000022, 그 다음으로 높은 숫자 는 1 + 2 × 2 -52 ≈ 1.00000000000000044입니다.

       + ------------------------------------------------- -------------- 부호 비트
      / + ------- + ---------------------------------------- -------------- 지수
     / / | + ------------------------------------------------- +-의미
    / / | / |
    0 01111111111 0000000000000000000000000000000000000000000000000000
                    = 1
    0 01111111111 0000000000000000000000000000000000000000000000000001
                    ≈ 1.00000000000000022
    0 01111111111 0000000000000000000000000000000000000000000000000010
                    ≈ 1.00000000000000044
    

    1.00000000000000022에서 1.00000000000000044로 점프했습니다. 1.0000000000000003을 저장할 방법이 없습니다. : 그것도 정수로 일어날 수 있습니다 Number.MAX_SAFE_INTEGER(9,007,199,254,740,991를) 형식으로 저장할 수있는 가장 높은 양의 정수 값 ii + 1모두 정확하게 표현할 수 (있는 스펙 ). 9,007,199,254,740,991과 9,007,199,254,740,992는 모두 표현할 수 있지만 다음 정수인 9,007,199,254,740,993은 표현할 수 없습니다. 9,007,199,254,740,992 이후에 나타낼 수있는 다음 정수는 9,007,199,254,740,994입니다. 다음은 비트 패턴입니다. 맨 오른쪽 (최하위) 비트에 유의하십시오.

       + ------------------------------------------------- -------------- 부호 비트
      / + ------- + ---------------------------------------- -------------- 지수
     / / | + ------------------------------------------------- +-의미
    / / | / |
    0 10000110011 1111111111111111111111111111111111111111111111111111
                    = 9007199254740991 (Number.MAX_SAFE_INTEGER)
    0 10000110100 0000000000000000000000000000000000000000000000000000
                    = 9007199254740992 (Number.MAX_SAFE_INTEGER + 1)
    x xxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
                      9007199254740993 (Number.MAX_SAFE_INTEGER + 2)를 저장할 수 없습니다.
    0 10000110100 0000000000000000000000000000000000000000000000000001
                    = 9007199254740994 (Number.MAX_SAFE_INTEGER + 3)
    

    형식은 밑이 2이고 해당 지수를 사용하면 최하위 비트가 더 이상 분수가 아닙니다. 값은 2입니다. 해제 (9,007,199,254,740,992) 또는 설정 (9,007,199,254,740,994) 일 수 있습니다. 그래서이 시점에서 우리는 정수 (정수) 척도에서도 정밀도를 잃기 시작했습니다. 우리 루프에 의미가 있습니다!

  4. i = 9,007,199,254,740,992루프를 완료 한 후 다시 i++제공 i = 9,007,199,254,740,992합니다. i다음 정수를 저장할 수없고 계산이 반올림되기 때문에 에는 변경 사항이 없습니다 . i우리가 변경하면 변경 i += 2되지만 i++변경할 수는 없습니다. 그래서 우리는 정상 상태에 도달했습니다. i절대 변경되지 않고 루프가 종료되지 않습니다.

다음은 다양한 관련 계산입니다.

if (!Number.MAX_SAFE_INTEGER) {
  // Browser doesn't have the Number.MAX_SAFE_INTEGER
  // property; shim it. Should use Object.defineProperty
  // but hey, maybe it's so old it doesn't have that either
  Number.MAX_SAFE_INTEGER = 9007199254740991;
}
var i = 0;
console.log(i, 1/i, 1/i > 0); // 0, Infinity, true
i++;
console.log(i, 1/i, 1/i > 0); // 1, 1, true
// ...eventually i is incremented all the way to Number.MAX_SAFE_INTEGER
i = Number.MAX_SAFE_INTEGER;
console.log(i, 1/i, 1/i > 0); // 9007199254740991 1.1102230246251568e-16, true
i++;
console.log(i, 1/i, 1/i > 0); // 9007199254740992 1.1102230246251565e-16, true
i++;
console.log(i, 1/i, 1/i > 0); // 9007199254740992 1.1102230246251565e-16, true (no change)
console.log(i == i + 1);      // true


답변

대답:

조건 1/i > 0은 항상 true로 평가됩니다.

  • 처음에는 그것 때문에 사실 1/0들을 평가에 InfinityInfinity > 0사실

  • 그것은 1/i > 0모두에게 사실 i < Infinity이며 i++결코 도달하지 않기 때문에 사실로 유지됩니다 Infinity.

i++도달 하지 Infinity않습니까? Number데이터 유형 의 제한된 정밀도로 인해 다음과 같은 값이 있습니다 i + 1 == i.

9007199254740992 + 1 == 9007199254740992 // true

일단 i값 (에 대응하는 것을 도달하면 ), 그 후에도 동일하게 유지한다 .Number.MAX_SAFE_INTEGER + 1i++

그러므로 우리는 무한 루프를 가지고 있습니다.


부록:

9007199254740992 + 1 == 9007199254740992?

JavaScript의 Number데이터 유형은 실제로 64 비트 IEEE 754 배정 밀도 float 입니다. 각각 Number은 분해되어 1 비트 부호, 11 비트 지수 및 52 비트 가수의 세 부분으로 저장됩니다. 그 값은 -1 sign × mantissa × 2 exponent 입니다.

9007199254740992 는 어떻게 표현됩니까? 로 1.0 × 2 (53) , 또는 이진 :

여기에 이미지 설명 입력

가수의 최하위 비트를 증가 시키면 다음으로 높은 숫자를 얻습니다.

여기에 이미지 설명 입력

그 숫자의 값은 1.00000000000000022… × 2 53 = 9007199254740994입니다.

그게 무슨 뜻입니까? Number900719925474099 2 또는 900719925474099 4 중 하나 일 수 있지만 그 사이에는 없습니다.

이제 900719925474099 2 + 1 을 나타 내기 위해 어떤 것을 선택 할까요? IEEE 754 반올림 규칙은 900719925474099 : 대답 제공 2 .


답변

Number.MAX_SAFE_INTEGER상수는 자바 스크립트의 최대 안전 정수를 나타냅니다. MAX_SAFE_INTEGER상수의 값을 갖는다 9007199254740991. 그 숫자 뒤에 이유는 자바 스크립트를 사용한다는 것입니다 배정 밀도 부동 소수점 형식 번호 에 지정된 IEEE 754 (2 – 만 안전하게 사이의 숫자를 나타낼 수 (53) – 1)과 2 (53) – 1이다.

이 문맥에서 안전은 정수를 정확하게 표현하고 정확하게 비교할 수있는 능력을 의미합니다. 예를 들어 는 수학적으로 잘못된로 Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2평가됩니다 true. 자세한 내용은를 참조하십시오 Number.isSafeInteger().

MAX_SAFE_INTEGER의 정적 속성 이므로 생성 한 객체 의 속성이 아닌 Number항상으로 사용합니다 .Number.MAX_SAFE_INTEGERNumber

최신 정보:

삭제 된 답변에 누군가 언급 : i무한대에 도달하지 않습니다. 이 도달하면 Number.MAX_SAFE_INTEGER, i++더 이상 변수를 증가하지 않습니다. 사실 이것은 정확 하지 않습니다 .

@TJ 크라우 더는 댓글 i = Number.MAX_SAFE_INTEGER; i++; i == Number.MAX_SAFE_INTEGER;입니다 false. 그러나 다음 반복은 변하지 않는 상태에 도달하므로 main의 대답은 정확합니다.

i예제에서 Infinity.


답변