Maximus Maximus - 1 year ago 43
Javascript Question

Does a 'for' loop stop if the condition is 1/i > 0?

Does the following

loop stop?

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

If so, when and why? I was told that it stops, but I was given no reason for that.

Answer Source

gotnull's and le_m's answers are both correct and useful, but in both cases I feel the the explanations cover the parts of what's happening without really laying them out clearly in order. This is a Community Wiki post doing that.

The loop won't stop in a correctly-implemented JavaScript engine. (The engine's host environment might eventually terminate it because it's endless, but that's another thing.)

Here's why:

  1. Initially, when i is 0, the condition 1/i > 0 is true because in JavaScript, 1/0 is Infinity, and Infinity > 0 is true.

  2. After that, i will be incremented and continue to grow as a positive integer value for a long time (a further 9,007,199,254,740,990 iterations). In all of those cases, 1/i will remain > 0 (although the values for 1/i get really small toward the end!) and so the loop continues up to and including the loop where i reaches the value Number.MAX_SAFE_INTEGER.

  3. Number.MAX_SAFE_INTEGER (9,007,199,254,740,991) is the highest positive integer value that an IEEE-754 double-precision binary number (the kind JavaScript uses) can accurately represent. Once we go past this point, we start losing precision even at the whole number (integer) scale.

  4. After the loop where i is Number.MAX_SAFE_INTEGER, i++ takes us to an inaccurate number. If you printed out the value of i at that point, it would say 9,007,199,254,740,992, but it isn't quite 9,007,199,254,740,992. Double precision numbers famously can't represent all numbers (0.1 + 0.2 == 0.3 is false, for instance), but we're used to thinking (erroneously) that it only affects the fractional part. It doesn't, and this is the point at which it starts affecting the whole-number part. 1/i is still > 0 so the loop continues.

  5. From that point forward, i++ doesn't change the value of i anymore; adding 1 to it doesn't change the bit pattern held for the number at all. Adding a higher number like 10 to it would, but adding 1 to it doesn't. So we've reached steady-state: i never changes, and the loop never terminates.

Here are the various relevant calculations:

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
console.log(i, 1/i, 1/i > 0); // 1, 1, true
// ...eventually i is incremented all the way to Number.MAX_SAFE_INTEGER
console.log(i, 1/i, 1/i > 0); // 9007199254740991 1.1102230246251568e-16, true
console.log(i, 1/i, 1/i > 0); // 9007199254740992 1.1102230246251565e-16, true
console.log(i, 1/i, 1/i > 0); // 9007199254740992 1.1102230246251565e-16, true (no change)
console.log(i == i + 1);      // true