Max*_*kyi 102 javascript
这个for
循环是否会停止?
for (var i=0; 1/i > 0; i++) {
}
Run Code Online (Sandbox Code Playgroud)
如果是的话,何时以及为何?我被告知它停止了,但我没有理由这样做.
作为调查的一部分,我写了很长很详细的文章,解释了幕后发生的一切 - 以下是关于JavaScript的数字类型你需要了解的内容
T.J*_*der 128
(我不是元内容的粉丝,但是:getnull和le_m的答案都是正确和有用的.它们最初是,并且在社区Wiki发布之后进行的编辑更是如此.这个CW的原始动机由于这些编辑很大程度上已经消失了,但它仍然有用,所以...另外:虽然只列出了几个作者,但许多其他社区成员已经大大帮助了已经折叠和清理的评论.不仅仅是CW的名字.)
循环不会在正确实现的JavaScript引擎中停止.(引擎的主机环境可能最终会终止它,因为它是无穷无尽的,但这是另一回事.)
原因如下:
最初,当i
是0
,条件1/i > 0
是正确的,因为在JavaScript中,1/0
是Infinity
和Infinity > 0
是真实的.
之后,i
将增加并继续增长为正整数值很长一段时间(另外9,007,199,254,740,991次迭代).在所有这些情况下,1/i
将保持不变> 0
(尽管到最后1/i
得到的值非常小!)因此循环继续到达并包括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:
+--------------------------------------------------------------- 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); 所以在这一点上,即使在整数(整数)范围内,我们也开始失去精度.这对我们的循环有影响!
完成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
评估Infinity
和Infinity > 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
+ 1
i++
因此,我们有一个无限循环.
为什么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.
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
.
归档时间: |
|
查看次数: |
6621 次 |
最近记录: |