这个“for”循环是否停止,为什么?为什么不呢? for(var i = 0; 1 / i> 0; i ++){}

for循环停止?

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

如果是这样,何时,为什么? 我被告知停止,但我没有理由。

Upddate

作为调查的一部分,我编写了相当冗长和详细的文章,解释了所有内容。 下面是您需要了解的JavaScript数字types

(我不喜欢元内容,但是: gotnull和le_m的答案都是正确和有用的,它们本来就是这样的 ,在这个社区维基发布之后的编辑更是如此 。大部分是由于这些编辑而消失的,但它仍然是有用的,所以…另外:虽然只列出了几个作者,但许多其他社区成员对已经被折叠和清理的评论大有帮助。不只是一个CW的名字。)


循环不会停在正确实现的JavaScript引擎中。 (引擎的主机环境可能最终会终止,因为它是无止境的,但那是另一回事。)

原因如下:

  1. 最初,当i0 ,条件1/i > 0是真实的,因为在JavaScript中, 1/i > 0 1/0Infinity ,并且Infinity > 0是真实的。

  2. 之后, i会增加,并继续作为一个正整数长时间增长(另外9,007,199,254,740,991迭代)。 在所有这些情况下, 1/i将保持> 0 (尽pipe1/i的值会变得非常小),所以循环继续到包括循环的地方,在那里达到值Number.MAX_SAFE_INTEGER

  3. JavaScript中的数字是IEEE-754双精度二进制浮点数,它是一种相当紧凑的格式(64位),它提供了快速计算和广泛的范围。 它通过将数字存储为一个符号位,一个11位指数和一个52位有效数字(尽pipe通过巧妙实际上得到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都可以精确地表示( spec )。 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将始终评估为真:

  • 最初这是真的,因为1/0评估为InfinityInfinity > 0为真

  • 它保持真实,因为1/i > 0对于所有的i < Infinity是正确的, i++永远不会到达Infinity

为什么i++从来没有达到Infinity ? 由于Number数据types的精度有限,因此有一个值i + 1 == i

 9007199254740992 + 1 == 9007199254740992 // true 

一旦i达到该值(对应于Number.MAX_SAFE_INTEGER + 1 ),它将保持不变,即使在i++

因此,我们有一个无限循环。


附录:

为什么是9007199254740992 + 1 == 9007199254740992

JavaScript的Number数据types实际上是一个64位的IEEE 754双精度浮点数 。 每个Number被拆解并存储为三部分:1位符号,11位指数和52位尾数。 其值是-1 符号 ×尾数×2 指数

9007199254740992代表什么? 由于1.0×2 53 ,或二进制:

在这里输入图像说明

增加尾数的最低位,我们得到下一个更高的数字:

在这里输入图像说明

该号码的值是1.00000000000000022 …×2 53 = 9007199254740994

那是什么意思? Number可以是900719925474099 2或900719925474099 4 ,但两者之间没有任何内容。

现在,我们select哪一个代表900719925474099 2 + 1 ? IEEE 754舍入规则给出了答案:900719925474099 2

Number.MAX_SAFE_INTEGER常量表示JavaScript中的最大安全整数。 MAX_SAFE_INTEGER常量的值为9007199254740991 。 这个数字背后的原因是,JavaScript使用IEEE 754中规定的双精度浮点格式数字 ,只能安全地表示 – (2 53 – 1)和2 53 – 1之间的数字。

在这种情况下,安全是指能够精确表示整数并正确比较它们。 例如, Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2将计算为true ,这在math上是不正确的。 有关更多信息,请参阅Number.isSafeInteger()

由于MAX_SAFE_INTEGERNumber的静态属性,因此您始终将其用作Number.MAX_SAFE_INTEGER ,而不是您创build的Number对象的属性。

更新:

有人提到被删除的答案: i永远无法达到无限。 一旦达到Number.MAX_SAFE_INTEGERi++不会再增加variables。 这实际上是正确的。

@TJ Crowder评论说, i = Number.MAX_SAFE_INTEGER; i++; i == Number.MAX_SAFE_INTEGER; i = Number.MAX_SAFE_INTEGER; i++; i == Number.MAX_SAFE_INTEGER;false 。 但是下一个迭代达到一个不变的状态,所以主要答案是正确的。

i在这个例子中永远不会到达Infinity