这个for
循环会停止吗?
for (var i=0; 1/i > 0; i++) {
}
如果是这样,什么时候以及为什么?有人告诉我它停止了,但是我没有理由这么做。更新日期
作为调查的一部分,我写了一篇冗长而详尽的文章,解释了幕后工作-Here is what you need to know about JavaScript’s Number type
最佳答案
(我不喜欢meta内容,但是:gotnull's和le_m's答案都是正确且有用的。它们本来就是,更是如此,所以在发布此社区Wiki后所做的编辑中更是如此。由于进行了这些修改,该CW在很大程度上消失了,但是它仍然有用,因此...。另外:虽然只列出了几位作者,但许多其他社区成员对已折叠并整理的评论也有很大帮助(这不只是名称上的CW。)
在正确实现的JavaScript引擎中,循环不会停止。 (引擎的宿主环境最终可能会终止它,因为它是无止境的,但这是另一回事。)
原因如下:
i
为0
时,条件1/i > 0
为true,因为在JavaScript中,1/0
为Infinity
,而Infinity > 0
为true。 i
将递增,并在很长一段时间内继续增长为正整数值(再进行9,007,199,254,740,991次迭代)。在所有这些情况下,1/i
仍将是> 0
(尽管1/i
的值实际上会使的很小!),因此循环继续进行,直到i
达到值Number.MAX_SAFE_INTEGER
的循环为止。 自然,只有这么多的有效位,所以不能存储每个数字。这是数字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 where i
and i + 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 in i
, because the next integer can't be stored and the calculation ends up rounding down. i
would change if we did i += 2
, but i++
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'循环会停止吗,为什么/为什么不呢? for(var i = 0; 1/i> 0; i++){},我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37827073/