programing tip

이 'for'루프가 중지되고 왜 / 왜 안됩니까?

itbloger 2020. 8. 16. 19:54
반응형

이 '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로 평가됩니다.

  • Initially it's true because 1/0 evaluates to Infinity and Infinity > 0 is true

  • It stays true since 1/i > 0 is true for all i < Infinity and i++ never reaches Infinity.

Why does i++ never reach Infinity? Due to the limited precision of the Number datatype, there is a value for which i + 1 == i:

9007199254740992 + 1 == 9007199254740992 // true

Once i reaches that value (which corresponds to Number.MAX_SAFE_INTEGER+ 1), it will stay the same even after i++.

We therefore have an infinite loop.


Appendix:

Why is 9007199254740992 + 1 == 9007199254740992?

JavaScript's Number datatype is actually an 64-bit IEEE 754 double precision float. Each Number is disassembled and stored as three parts: 1-bit sign, 11-bit exponent, and 52-bit mantissa. Its value is -1 sign × mantissa × 2 exponent.

How is 9007199254740992 represented? As 1.0 × 2 53, or in binary:

enter image description here

Incrementing the mantissa's least significant bit, we get the next higher number:

enter image description here

The value of that number is 1.00000000000000022… × 2 53 = 9007199254740994

What does that mean? Number can either be 9007199254740992 or 9007199254740994, but nothing in between.

Now, which one shall we chose to represent 9007199254740992 + 1? The IEEE 754 rounding rules give the answer: 9007199254740992.


The Number.MAX_SAFE_INTEGER constant represents the maximum safe integer in JavaScript. The MAX_SAFE_INTEGER constant has a value of 9007199254740991. The reasoning behind that number is that JavaScript uses double-precision floating-point format numbers as specified in IEEE 754 and can only safely represent numbers between -(253 - 1) and 253 - 1.

Safe in this context refers to the ability to represent integers exactly and to correctly compare them. For example, Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 will evaluate to true, which is mathematically incorrect. See Number.isSafeInteger() for more information.

Because MAX_SAFE_INTEGER is a static property of Number, you always use it as Number.MAX_SAFE_INTEGER, rather than as a property of a Number object you created.

UPDATE:

Someone in an answer that was deleted mentioned: i will never reach infinity. Once it reaches Number.MAX_SAFE_INTEGER, i++ doesn't increment the variable anymore. This is in fact not correct.

@T.J. Crowder comments that i = Number.MAX_SAFE_INTEGER; i++; i == Number.MAX_SAFE_INTEGER; is false. But the next iteration reaches an unchanging state, so the answer in main is correct.

i in the example never reaches Infinity.

참고URL : https://stackoverflow.com/questions/37827073/does-this-for-loop-stop-and-why-why-not-for-var-i-0-1-i-0-i

반응형