这个“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引擎中。 (引擎的主机环境可能最终会终止,因为它是无止境的,但那是另一回事。)
原因如下:
-
最初,当
i
为0
,条件1/i > 0
是真实的,因为在JavaScript中,1/i > 0
1/0
是Infinity
,并且Infinity > 0
是真实的。 -
之后,
i
会增加,并继续作为一个正整数长时间增长(另外9,007,199,254,740,991迭代)。 在所有这些情况下,1/i
将保持> 0
(尽pipe1/i
的值会变得非常小),所以循环继续到包括循环的地方,在那里达到值Number.MAX_SAFE_INTEGER
。 -
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)是格式可以容纳的最高的正整数值,其中i
和i + 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); 所以在这一点上,即使在整数(整数)范围内,我们也开始失去精度。 这对我们的循环有影响!
-
在完成
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
评估为Infinity
,Infinity > 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_INTEGER
是Number
的静态属性,因此您始终将其用作Number.MAX_SAFE_INTEGER
,而不是您创build的Number
对象的属性。
更新:
有人提到被删除的答案: i
永远无法达到无限。 一旦达到Number.MAX_SAFE_INTEGER
, i++
不会再增加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
。