这个for循环会停止吗?
for (var i=0; 1/i > 0; i++) {
}
如果是这样,什么时候以及为什么?有人告诉我它停止了,但是我没有理由这么做。
更新日期
作为调查的一部分,我写了一篇冗长而详细的文章,解释了幕后工作的一切- 这是您需要了解的JavaScript Number类型的知识
这个for循环会停止吗?
for (var i=0; 1/i > 0; i++) {
}
如果是这样,什么时候以及为什么?有人告诉我它停止了,但是我没有理由这么做。
作为调查的一部分,我写了一篇冗长而详细的文章,解释了幕后工作的一切- 这是您需要了解的JavaScript Number类型的知识
Answers:
(我不喜欢meta内容,但是:gotnull和le_m的答案都是正确且有用的。它们本来就是正确的,在发布此Community Wiki之后所做的编辑更是如此。此CW的原始动机是这些编辑在很大程度上使它消失了,但是它仍然有用,所以...另外:虽然只列出了几位作者,但许多其他社区成员对已被折叠和整理的评论也提供了很大的帮助。不只是名字上的CW。)
在正确实现的JavaScript引擎中,循环不会停止。(引擎的主机环境最终可能会终止它,因为它是无止境的,但这是另一回事。)
原因如下:
最初i是什么时候0,条件1/i > 0为true,因为在JavaScript中,1/0is Infinity和Infinity > 0true。
之后,i将递增,并在很长一段时间内继续增长为正整数值(进一步的9,007,199,254,740,991迭代)。在所有这些情况下,1/i都将保留> 0(尽管1/iget 的值真正朝着端小!),继续循环直至并包括在那里,循环等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 0000000000000000000000000000000000000000000000000000000000 = 1 0 01111111111 0000000000000000000000000000000000000000000000000000000001 ≈1.00000000000000022 0 01111111111 0000000000000000000000000000000000000000000000000000000010 ≈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 1111111111111111111111111111111111111111111111111111111 = 9007199254740991(Number.MAX_SAFE_INTEGER) 0 10000110100 0000000000000000000000000000000000000000000000000000000000 = 9007199254740992(Number.MAX_SAFE_INTEGER + 1) x xxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 9007199254740993(Number.MAX_SAFE_INTEGER + 2)无法存储 0 10000110100 0000000000000000000000000000000000000000000000000000000001 = 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:
最初是真的,因为1/0评估为Infinity,并Infinity > 0为真
它保持真实,因为1/i > 0对所有人而言都是真实的i < Infinity,i++永远不会达到Infinity。
为什么i++从来没有达到Infinity?由于Number数据类型的精度有限,因此存在一个i + 1 == i:
9007199254740992 + 1 == 9007199254740992 // true
一旦i达到该值(对应于Number.MAX_SAFE_INTEGER + 1),它甚至会后保持不变i++。
因此,我们有一个无限循环。
为什么是 9007199254740992 + 1 == 9007199254740992呢?
JavaScript的Number数据类型实际上是64位IEEE 754双精度float。每个组件都Number被分解并存储为三部分:1位符号,11位指数和52位尾数。其值为-1 符号 ×尾数×2 指数。
9007199254740992如何表示?为1.0×2 53或二进制:

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

该数字的值是1.00000000000000022…×2 53 = 9007199254740994
那是什么意思?Number可以是900719925474099 2或900719925474099 4,但两者之间什么也不能。
现在,我们应该选择哪一个代表900719925474099 2 + 1?在IEEE 754舍入规则给出了答案:900719925474099 2。
for (var i = 0; i < Infinity; i += 1E306);。但是我知道你来自哪里;)
该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,这在数学上是不正确的。看到Number.isSafeInteger()以获取更多信息。
因为MAX_SAFE_INTEGER是的静态属性Number,所以您始终将其用作Number.MAX_SAFE_INTEGER,而不是用作Number创建的对象的属性。
更新:
答案中有人提及:i永远不会达到无限。一旦达到Number.MAX_SAFE_INTEGER,i++就不再增加变量。这实际上是不正确的。
@TJ Crowder评论i = Number.MAX_SAFE_INTEGER; i++; i == Number.MAX_SAFE_INTEGER;是false。但是下一次迭代达到不变状态,因此main中的答案是正确的。
i在这个例子中永远都无法实现Infinity。
9007199254740992 + 1是9007199254740992。
for (var i=0; NaN > 0; i++) { console.log(i); }将不会产生任何东西。
1/i > 0)将为false,因为if i是0,1/iis NaN和false,所以根本不会输入循环体NaN > 0。