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

Max*_*kyi 102 javascript

这个for循环是否会停止?

for (var i=0; 1/i > 0; i++) {
}
Run Code Online (Sandbox Code Playgroud)

如果是的话,何时以及为何?我被告知它停止了,但我没有理由这样做.

Upddate

作为调查的一部分,我写了很长很详细的文章,解释了幕后发生的一切 - 以下是关于JavaScript的数字类型你需要了解的内容

T.J*_*der 128

(我不是元内容的粉丝,但是:getnullle_m的答案都是正确和有用的.它们最初是,并且在社区Wiki发布之后进行的编辑更是如此.这个CW的原始动机由于这些编辑很大程度上已经消失了,但它仍然有用,所以...另外:虽然只列出了几个作者,但许多其他社区成员已经大大帮助了已经折叠和清理的评论.不仅仅是CW的名字.)


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

原因如下:

  1. 最初,当i0,条件1/i > 0是正确的,因为在JavaScript中,1/0InfinityInfinity > 0是真实的.

  2. 之后,i将增加并继续增长为正整数值很长一段时间(另外9,007,199,254,740,991次迭代).在所有这些情况下,1/i将保持不变> 0(尽管到最后1/i得到的值非常小!)因此循环继续到达并包括i达到值的循环Number.MAX_SAFE_INTEGER.

  3. JavaScript中的数字是IEEE-754双精度二进制浮点数,相当紧凑的格式(64位),可提供快速计算和大范围.它通过将数字存储为符号位,11位指数和52位有效数来实现这一点(尽管通过聪明,它实际上获得了53位精度).它是二进制(基数2)浮点:有效数(加上一些聪明)给出了值,指数给出了数字的大小.

    当然,只有这么多有效位,不是每个数字都可以存储.这里是数字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
    

    注意从1.00000000000000022跳转到1.00000000000000044; 没有办法存储1.0000000000000003.整数也可能发生这种情况:Number.MAX_SAFE_INTEGER(9,007,199,254,740,991)是格式可以容纳的最高正整数值,i并且i + 1两者都可以完全表示(规范).可以表示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.这是位模式,请注意最右边(最不重要)位:

       +--------------------------------------------------------------- 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)
    

    请记住,格式是基数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
Run Code Online (Sandbox Code Playgroud)


le_*_*e_m 79

回答:

条件1/i > 0将始终评估为true:

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

  • 它保持真实,因为1/i > 0对所有人都是如此i < Infinity,i++永远不会到达Infinity.

为什么i++永远不会到达Infinity?由于Number数据类型的精度有限,因此有一个值i + 1 == i:

9007199254740992 + 1 == 9007199254740992 // true
Run Code Online (Sandbox Code Playgroud)

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

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


附录:

为什么9007199254740992 + 1 == 9007199254740992

JavaScript的Number数据类型实际上是64位IEEE 754双精度浮点数.每个都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.

  • 简短而正确,优于目前接受的答案 (9认同)
  • 我不知道"社区wiki得到"这个词的答案.这与stackoverflow有什么关系?如果这是外国链接,则应提供链接.stackoverflow上接受的答案总是可以改变,所处的状态不是最终的. (2认同)

fuz*_*uzz 27

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克罗德评论说i = Number.MAX_SAFE_INTEGER; i++; i == Number.MAX_SAFE_INTEGER;false.但是下一次迭代达到了一个不变的状态,所以主要的答案是正确的.

i在示例中永远不会到达Infinity.

  • 具体而言,`9007199254740992 + 1`是`9007199254740992`. (2认同)
  • @GerardoFurtado:在这种情况下,循环将停止.根本不会输入循环体,因为第一次测试(`1/i> 0`)将是假的,因为如果`i`是'0`,`1/i`是'NaN`,并且` NaN> 0`是假的. (2认同)