104 votes

Cette boucle "pour" s'arrête-t-elle et pourquoi / pourquoi pas? pour (var i = 0; 1 / i> 0; i ++) {}

Cette for boucle jamais s'arrêter?

for (var i=0; 1/i > 0; i++) {
}

Si oui, quand et pourquoi? On m'a dit que ça s'arrête, mais on m'a donné aucune raison pour que.

Upddate

Dans le cadre de l'enquête que j'ai écrit assez longue et détaillée de l'article qui explique tout ce qu'il se passe sous le capot - Voici ce que vous devez savoir à propos de JavaScript du type de Numéro

129voto

T.J. Crowder Points 285826

(Je ne suis pas un fan de la méta-contenu, mais: gotnull de et le_m de réponses sont à la fois juste et utile. Ils ont été, et sont encore plus avec les modifications apportées après ce Wiki de la Communauté a été posté. La motivation initiale de ce CW est en grande partie en raison de ces modifications, mais il reste utile, donc... Aussi: Alors qu'il ya seulement un couple des auteurs cités, de nombreux autres membres de la communauté ont grandement aidé à des commentaires qui ont été pliées et nettoyé. Ce n'est pas juste un mc en nom.)


La boucle ne s'arrêtera pas dans un correctement mises en oeuvre moteur JavaScript. (Le moteur de l'hôte de l'environnement pourrait éventuellement y mettre fin parce que c'est sans fin, mais c'est autre chose.)

Voici pourquoi:

  1. Initialement, lorsqu' i est 0, la condition 1/i > 0 est vrai, car en JavaScript, 1/0 est Infinity, et Infinity > 0 est vrai.

  2. Après, i sera incrémenté et de continuer à grandir comme une valeur entière positive pour une longue période (un autre 9,007,199,254,740,991 itérations). Dans tous ces cas, 1/i resteront > 0 (bien que les valeurs de 1/i obtenir vraiment petit vers la fin!) et donc, la boucle continue jusqu'à et y compris la boucle où i atteint la valeur Number.MAX_SAFE_INTEGER.

  3. Les numéros sont en JavaScript IEEE-754 double précision en virgule flottante binaire, un format assez compact (64 bits), qui fournit pour des calculs rapides et un vaste éventail. Il le fait en stockant le nombre comme un bit de signe, 11 bits d'exposant et 52 bits significande (bien que grâce à l'astuce c'est de 53 bits de précision). C'est binaire (base 2) virgule flottante: Le significande (plus une certaine intelligence) nous donne la valeur, et l'exposant nous donne l'ampleur du nombre.

    Naturellement, avec autant de bits significatifs, et pas à chaque numéro peut être stockée. Ici est le nombre 1, et le plus grand nombre après le 1er que le format de magasin, 1 + 2-52 ≈ 1.00000000000000022, et le suivant le plus élevé après que 1 + 2 × 2-52 ≈ 1.00000000000000044:

     +--------------------------------------------------------------- bit de signe
     / +-------+------------------------------------------------------ exposant
     / / | +-------------------------------------------------+- significande
    / / | / |
    0 01111111111 0000000000000000000000000000000000000000000000000000
     = 1
    0 01111111111 0000000000000000000000000000000000000000000000000001
     ≈ 1.00000000000000022
    0 01111111111 0000000000000000000000000000000000000000000000000010
     ≈ 1.00000000000000044
    

    Notez que le saut de 1.00000000000000022 à 1.00000000000000044; il n'y a aucun moyen de stocker 1.0000000000000003. Ce qui peut arriver avec des entiers: Number.MAX_SAFE_INTEGER (9,007,199,254,740,991) est la plus haute valeur entière positive que le format peut contenir où i et i + 1 sont à la fois exactement représentable (spec). Les deux 9,007,199,254,740,991 et 9,007,199,254,740,992 peut être représenté, mais la prochaine entier, 9,007,199,254,740,993, ne le peuvent pas; nombre entier le plus proche, nous pouvons représenter après 9,007,199,254,740,992 est 9,007,199,254,740,994. Voici les modèles de bits, la note la plus à droite (le moins significatif) bits:

     +--------------------------------------------------------------- bit de signe
     / +-------+------------------------------------------------------ exposant
     / / | +-------------------------------------------------+- significande
    / / | / |
    0 10000110011 1111111111111111111111111111111111111111111111111111
     = 9007199254740991 (en Nombre.MAX_SAFE_INTEGER)
    0 10000110100 0000000000000000000000000000000000000000000000000000
     = 9007199254740992 (en Nombre.MAX_SAFE_INTEGER + 1)
    x xxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
     9007199254740993 (en Nombre.MAX_SAFE_INTEGER + 2) ne peuvent pas être stockés
    0 10000110100 0000000000000000000000000000000000000000000000000001
     = 9007199254740994 (en Nombre.MAX_SAFE_INTEGER + 3)
    

    Rappelez-vous, le format de la base 2, et en exposant le bit le moins significatif n'est plus fractionnaire; il a une valeur de 2. Il peut être désactivé (9,007,199,254,740,992) ou sur (9,007,199,254,740,994); donc, à ce moment, nous avons commencé à perdre de précision, même au nombre entier (integer) de l'échelle. Qui a des implications pour notre boucle!

  4. Après avoir terminé l' i = 9,007,199,254,740,992 boucle, i++ nous donne ... i = 9,007,199,254,740,992 nouveau; il n'y a pas de changement en i, parce que le prochain entier ne peuvent pas être stockées et le calcul se termine arrondi vers le bas. i changerait si nous n' i += 2, mais i++ peut pas la changer. Nous avons donc atteint l'état d'équilibre: i ne change jamais, et la boucle se termine jamais.

Voici les différents calculs:

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

78voto

le_m Points 758

Réponse:

La condition 1/i > 0 toujours true:

  • D'abord c'est vrai, car 1/0 évalue Infinity et Infinity > 0 est vrai

  • Il reste fidèle depuis 1/i > 0 est vrai pour tous les i < Infinity et i++ jamais atteint Infinity.

Pourquoi est - i++ n'atteignent jamais Infinity? En raison de la précision limitée de la Number type de données, il existe une valeur pour qui i + 1 == i:

9007199254740992 + 1 == 9007199254740992 // true

Une fois i atteint cette valeur (qui correspond à l' Number.MAX_SAFE_INTEGER+ 1), il restera le même, même après l' i++.

Nous avons donc une boucle infinie.


Annexe:

Pourquoi est - 9007199254740992 + 1 == 9007199254740992?

JavaScript Number type de données est en fait un 64 bits IEEE 754 double précision float. Chaque Number est démonté et stocké sous forme de trois parties: 1 bit de signe, 11 bits d'exposant et 52 bits de mantisse. Sa valeur est -1 signe × mantisse × 2 exposant.

Comment est 9007199254740992 représentés? Comme 1.0 × 2 53, soit en binaire:

enter image description here

L'incrémentation de la mantisse du bit le moins significatif, nous obtenons le nombre supérieur suivant:

enter image description here

La valeur de ce nombre est 1.00000000000000022... × 2 53 = 9007199254740994

Qu'est-ce que cela signifie? Number peut être 9007199254740992 ou 9007199254740994, mais rien entre les deux.

Maintenant, que l'on doit, nous avons choisi de représenter 9007199254740992 + 1? Les règles d'arrondi IEEE 754 donner la réponse: 9007199254740992.

27voto

gotnull Points 4918

L' Number.MAX_SAFE_INTEGER constante représente le maximum de sécurité entier en JavaScript. L' MAX_SAFE_INTEGER constante a une valeur de 9007199254740991. Le raisonnement derrière ce chiffre, c'est que le JavaScript utilise des double-precision floating-point en forme de nombres tel que spécifié dans la norme IEEE 754 et la seule façon de représenter les nombres entre(253 - 1) et 253 - 1.

Coffre-fort dans ce contexte, fait référence à la capacité de représenter des nombres entiers exactement et correctement les comparer. Par exemple, Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 donnera true, ce qui est mathématiquement incorrect. Voir Number.isSafeInteger() pour plus d'informations.

Parce qu' MAX_SAFE_INTEGER est une propriété statique de l' Number, vous pouvez toujours l'utiliser comme Number.MAX_SAFE_INTEGER, plutôt que comme une propriété d'un Number objet que vous avez créé.

Mise à JOUR:

Quelqu'un à une réponse qui a été supprimé mentionné: i ne sera jamais atteindre l'infini. Une fois qu'il atteint Number.MAX_SAFE_INTEGER, i++ n'a pas d'incrémentation de la variable de plus. Ce n'est pas correct.

@T. J. Crowder commentaires qu' i = Number.MAX_SAFE_INTEGER; i++; i == Number.MAX_SAFE_INTEGER; est false. Mais la prochaine itération atteint un état immuable, donc la réponse en main est correcte.

i dans l'exemple n'atteint jamais l' Infinity.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X