Este for
loop nunca para?
for (var i=0; 1/i > 0; i++) {
}
Em caso afirmativo, quando e por quê? Disseram-me que parava, mas não me deram razão para isso.
Upddate
Como parte da investigação, escrevi um artigo bastante longo e detalhado que explica tudo o que está acontecendo nos bastidores - Aqui está o que você precisa saber sobre o tipo de número do JavaScript
javascript
Max Koretskyi
fonte
fonte
Number.MAX_SAFE_INTEGER + 1
.Respostas:
(Não sou fã de meta-conteúdo, mas: as respostas de gotnull's e le_m's estão corretas e úteis. Elas eram originalmente, e são ainda mais com as edições feitas depois que este Community Wiki foi postado. A motivação original para este CW desapareceu em grande parte como resultado dessas edições, mas continua útil, então ... Além disso: Embora haja apenas alguns autores listados, muitos outros membros da comunidade ajudaram muito com os comentários que foram dobrados e limpos. não é apenas um CW no nome.)
O loop não para em um mecanismo JavaScript implementado corretamente. (O ambiente de host do mecanismo pode eventualmente encerrá-lo porque é infinito, mas isso é outra coisa.)
Aqui está o porquê:
Inicialmente, quando
i
é0
, a condição1/i > 0
é verdadeira porque em JavaScript,1/0
éInfinity
eInfinity > 0
é verdadeiro.Depois disso,
i
será incrementado e continuará a crescer como um valor inteiro positivo por um longo tempo (mais 9.007.199.254.740.991 iterações). Em todos esses casos,1/i
permanecerá> 0
(embora os valores de1/i
fiquem muito pequenos no final!) E assim o loop continua até e incluindo o loop ondei
atinge o valorNumber.MAX_SAFE_INTEGER
.Os números em JavaScript são de ponto flutuante binário de precisão dupla IEEE-754, um formato bastante compacto (64 bits) que fornece cálculos rápidos e uma vasta gama. Ele faz isso armazenando o número como um bit de sinal, um expoente de 11 bits e um significando de 52 bits (embora, por meio da inteligência, ele na verdade obtenha 53 bits de precisão). É ponto flutuante binário (base 2): o significando (mais alguma inteligência) nos dá o valor, e o expoente nos dá a magnitude do número.
Naturalmente, com tantos bits significativos, nem todos os números podem ser armazenados. Aqui está o número 1 e o próximo número mais alto depois de 1 que o formato pode armazenar, 1 + 2 -52 ≈ 1.00000000000000022, e o próximo número mais alto depois desse 1 + 2 × 2 -52 ≈ 1.00000000000000044:
Observe o salto de 1.00000000000000022 para 1.00000000000000044; não há como armazenar 1.0000000000000003. Isso também pode acontecer com inteiros:
Number.MAX_SAFE_INTEGER
(9.007.199.254.740.991) é o valor inteiro positivo mais alto que o formato pode conter, ondei
ei + 1
são ambos representáveis exatamente ( especificação ). Ambos 9.007.199.254.740.991 e 9.007.199.254.740.992 podem ser representados, mas o próximo número inteiro, 9.007.199.254.740.993, não pode; o próximo número inteiro que podemos representar após 9.007.199.254.740.992 é 9.007.199.254.740.994. Aqui estão os padrões de bits, observe o bit mais à direita (menos significativo):Lembre-se de que o formato é de base 2 e, com esse expoente, o bit menos significativo não é mais fracionário; tem um valor de 2. Pode ser desativado (9.007.199.254.740.992) ou ativado (9.007.199.254.740.994); então, neste ponto, começamos a perder a precisão mesmo na escala de número inteiro (inteiro). O que tem implicações para o nosso loop!
Depois de completar o
i = 9,007,199,254,740,992
loop,i++
dá-nos ...i = 9,007,199,254,740,992
novamente; não há alteração emi
, porque o próximo inteiro não pode ser armazenado e o cálculo acaba sendo arredondado para baixo.i
mudaria se o fizéssemosi += 2
, masi++
não podemos mudar. Assim, alcançamos o estado estacionário:i
nunca muda e o loop nunca termina.Aqui estão os vários cálculos relevantes:
fonte
Responda:
A condição
1/i > 0
sempre será avaliada como verdadeira:Inicialmente, é verdade porque
1/0
avaliaInfinity
eInfinity > 0
é verdadeiroPermanece verdadeiro, pois
1/i > 0
é verdadeiro para todosi < Infinity
ei++
nunca atingeInfinity
.Por que
i++
nunca chegaInfinity
? Devido à precisão limitada doNumber
tipo de dados, há um valor para o quali + 1 == i
:Depois de
i
atingir esse valor (que corresponde a ), ele permanecerá o mesmo mesmo depois .Number.MAX_SAFE_INTEGER
+ 1
i++
Portanto, temos um loop infinito.
Apêndice:
Porque é
9007199254740992 + 1 == 9007199254740992
?O
Number
tipo de dados do JavaScript é, na verdade, um flutuante de precisão dupla IEEE 754 de 64 bits . Cada umNumber
é desmontado e armazenado em três partes: sinal de 1 bit, expoente de 11 bits e mantissa de 52 bits. Seu valor é -1 sinal × mantissa × 2 expoente .Como 9007199254740992 é representado? Como 1,0 × 2 53 ou em binário:
Incrementando o bit menos significativo da mantissa, obtemos o próximo número mais alto:
O valor desse número é 1.00000000000000022… × 2 53 = 9007199254740994
O que isso significa?
Number
pode ser 900719925474099 2 ou 900719925474099 4 , mas nada no meio.Agora, qual escolheremos para representar 900719925474099 2 + 1 ? As regras de arredondamento IEEE 754 fornecem a resposta: 900719925474099 2 .
fonte
for (var i = 0; i < Infinity; i += 1E306);
. Mas eu entendi de onde você está vindo;)A
Number.MAX_SAFE_INTEGER
constante representa o número inteiro seguro máximo em JavaScript. AMAX_SAFE_INTEGER
constante tem um valor de9007199254740991
. O raciocínio por trás desse número é que o JavaScript usa números de formato de ponto flutuante de precisão dupla conforme especificado no IEEE 754 e só pode representar com segurança números entre - (2 53 - 1) e 2 53 - 1.Seguro neste contexto refere-se à capacidade de representar inteiros exatamente e compará-los corretamente. Por exemplo,
Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2
irá avaliar paratrue
, o que é matematicamente incorreto. VejaNumber.isSafeInteger()
para mais informações.Por
MAX_SAFE_INTEGER
ser uma propriedade estática deNumber
, você sempre a usa comoNumber.MAX_SAFE_INTEGER
, e não como uma propriedade de umNumber
objeto que criou.ATUALIZAR:
Alguém em uma resposta que foi deletada mencionou:
i
nunca alcançará o infinito. Quando atingeNumber.MAX_SAFE_INTEGER
,i++
não incrementa mais a variável. Na verdade, isso não é correto.@TJ Crowder comenta que
i = Number.MAX_SAFE_INTEGER; i++; i == Number.MAX_SAFE_INTEGER;
éfalse
. Mas a próxima iteração atinge um estado imutável, então a resposta principal está correta.i
no exemplo nunca chegaInfinity
.fonte
9007199254740992 + 1
é9007199254740992
.for (var i=0; NaN > 0; i++) { console.log(i); }
não vai produzir nada.1/i > 0
) seria falso, pois ifi
é0
,1/i
éNaN
eNaN > 0
é falso.