这个 for
循环会停止吗?
for (var i=0; 1/i > 0; i++) {
}
如果是,何时以及为什么?有人告诉我它停止了,但我没有得到任何理由。
更新
作为调查的一部分,我写了一篇相当冗长和详细的文章,解释了幕后发生的一切 - Here is what you need to know about JavaScript’s Number type
最佳答案
(我不是元内容的粉丝,但是:gotnull's 和 le_m's 答案既正确又有用。它们最初是,而且更是如此在发布此社区 Wiki 后进行的编辑。由于这些编辑,此 CW 的原始动机在很大程度上消失了,但它仍然有用,所以...另外:虽然只列出了几个作者,但还有许多其他作者社区成员对已折叠和清理的评论提供了很大帮助。这不仅仅是名义上的 CW。)
循环不会在正确实现的 JavaScript 引擎中停止。 (引擎的宿主环境最终可能会终止它,因为它是无穷无尽的,但那是另一回事。)
原因如下:
最初,当
i
为0
时,条件1/i > 0
为真,因为在 JavaScript 中,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 double 二进制 float ,这是一种相当紧凑的格式(64 位),可提供快速计算和广泛的范围。它通过将数字存储为一个符号位、一个 11 位指数和一个 52 位有效数来实现这一点(尽管通过巧妙它实际上获得了 53 位精度)。它是二进制(以 2 为底) float :有效数字(加上一些巧妙的技巧)为我们提供了值,指数为我们提供了数字的大小。
自然地,只有这么多有效位,并不是每个数字都可以存储。这里是数字 1,以及格式可以存储的 1 之后的下一个最高数字,1 + 2-52 ≈ 1.00000000000000022,然后是 1 + 2 × 2-52 ≈ 1.00000000000000044:
+--------------------------------------------------------------- sign bit / +-------+------------------------------------------------------ exponent / / | +-------------------------------------------------+- significand / / | / | 0 01111111111 0000000000000000000000000000000000000000000000000000 = 1 0 01111111111 0000000000000000000000000000000000000000000000000001 ≈ 1.00000000000000022 0 01111111111 0000000000000000000000000000000000000000000000000010 ≈ 1.00000000000000044
Note the jump from 1.00000000000000022 to 1.00000000000000044; there's no way to store 1.0000000000000003. That can happen with integers, too:
Number.MAX_SAFE_INTEGER
(9,007,199,254,740,991) is the highest positive integer value that the format can hold wherei
andi + 1
are both exactly representable (spec). Both 9,007,199,254,740,991 and 9,007,199,254,740,992 can be represented, but the next integer, 9,007,199,254,740,993, cannot; the next integer we can represent after 9,007,199,254,740,992 is 9,007,199,254,740,994. Here are the bit patterns, note the rightmost (least significant) bit:+--------------------------------------------------------------- sign bit / +-------+------------------------------------------------------ exponent / / | +-------------------------------------------------+- significand / / | / | 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) can't be stored 0 10000110100 0000000000000000000000000000000000000000000000000001 = 9007199254740994 (Number.MAX_SAFE_INTEGER + 3)
Remember, the format is base 2, and with that exponent the least significant bit is no longer fractional; it has a value of 2. It can be off (9,007,199,254,740,992) or on (9,007,199,254,740,994); so at this point, we've started to lose precision even at the whole number (integer) scale. Which has implications for our loop!
After completing the
i = 9,007,199,254,740,992
loop,i++
gives us ...i = 9,007,199,254,740,992
again; there's no change ini
, because the next integer can't be stored and the calculation ends up rounding down.i
would change if we didi += 2
, buti++
can't change it. So we've reached steady-state:i
never changes, and the loop never terminates.
Here are the various relevant calculations:
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
关于javascript - 这个 'for' 循环是否停止,为什么/为什么不停止?对于 (var i=0; 1/i > 0; i++) { },我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37827073/