이 'for'루프가 중지되고 왜 / 왜 안됩니까? for (var i = 0; 1 / i> 0; i ++) {}
이 for
루프가 멈추나요?
for (var i=0; 1/i > 0; i++) {
}
그렇다면 언제, 왜? 멈춘다 고 들었지만 그럴 이유가 없었습니다.
업데이트
조사의 일환으로 내부에서 일어나는 모든 일을 설명하는 매우 길고 자세한 기사를 작성했습니다. JavaScript의 숫자 유형에 대해 알아야 할 사항은 다음과 같습니다.
(저는 메타 콘텐츠의 팬은 아니지만 : gotnull 과 le_m의 답변은 정확하고 유용합니다. 원래는 이 커뮤니티 위키가 게시 된 후 편집 한 내용 이 훨씬 더 많습니다 .이 CW의 원래 동기는 대부분의 편집의 결과로 사라졌지 만 여전히 유용합니다. 따라서 ... 또한 목록에 작성자가 몇 명 밖에 없지만 다른 많은 커뮤니티 회원들이 주석을 접고 정리하는 데 크게 도움을주었습니다. 이름에서 CW가 아닙니다.)
루프는 올바르게 구현 된 JavaScript 엔진에서 멈추지 않습니다. (엔진의 호스트 환경은 끝이 없기 때문에 결국 종료 될 수 있지만 이는 또 다른 문제입니다.)
그 이유는 다음과 같습니다.
때 처음
i
이며0
, 조건은1/i > 0
자바 스크립트, 때문에 사실1/0
입니다Infinity
, 그리고Infinity > 0
사실이다.그 후,
i
증가하고 오랫동안 양의 정수 값으로 계속 증가합니다 (추가 9,007,199,254,740,991 회 반복). 그 모든 경우에1/i
남아있을 것이다> 0
(비록에 대한 값을1/i
얻을 정말 끝을 향해 작은!) 루프는 루프에 포함까지 계속 그렇게i
값에 도달Number.MAX_SAFE_INTEGER
.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를) 형식으로 저장할 수있는 가장 높은 양의 정수 값i
과i + 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) 일 수 있습니다. 그래서이 시점에서 우리는 정수 (정수) 척도에서도 정밀도를 잃기 시작했습니다. 우리 루프에 의미가 있습니다!
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 toInfinity
andInfinity > 0
is trueIt stays true since
1/i > 0
is true for alli < Infinity
andi++
never reachesInfinity
.
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:
Incrementing the mantissa's least significant bit, we get the next higher number:
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
.
'programing tip' 카테고리의 다른 글
if-condition-assignment 한 줄 (0) | 2020.08.16 |
---|---|
전체 S3 버킷에 대한 캐시 제어를 자동으로 설정 (버킷 정책 사용?) (0) | 2020.08.16 |
C 함수 내부의 정적 변수 (0) | 2020.08.16 |
Java에 Null OutputStream이 있습니까? (0) | 2020.08.16 |
하위 도메인없이 유효한 도메인 이름과 일치하는 정규 표현식은 무엇입니까? (0) | 2020.08.16 |