As a joke the other day I posted a code snippet on Mastodon:
for (var i = -Infinity; i < Infinity; i++) { /* this should cover all possibilities */ }
Such an infinite loop is not possible, as adding 1 to -Infinity just gives you -Infinity again, and you never get anywhere. ;)
But even if you started from the minimum representable individual number in a double-precision floating point you wouldn’t actually iterate anywhere because there’s not enough precision to represent the added 1.
Which got me thinking, how *would* you iterate over the entire set of floating point numbers between -Infinity to +Infinity, knowing that the intervals between the numbers are variable?
Well if you want to get everything, including non-integral values, you can iterate over the available range of exponents and fractional values, and either bit-shift them together manually (ick!) or multiply/add/pow them together in floating point land.
Something like this:
function iterate_all_floats(callback) { // exponent is additively biased in the binary rep, // so we go from negative to positive vals. let min_exp = -(Math.pow(2, 10) - 2); // all binary 1s are reserved let max_exp = Math.pow(2, 10) - 1; let min_frac = 0; let max_frac = Math.pow(2, 52) - 1; let frac_divisor = Math.pow(2, 52); let min_sub = 0; let max_sub = Math.pow(2, 52) - 1; let sub_divisor = Math.pow(2, 52); callback(-Infinity); // Start from the biggest negative numbers and go up towards -0 for (let exp = max_exp; exp >= min_exp; exp--) { for (let frac = max_frac; frac >= min_frac; frac--) { callback(-(1.0 + frac / frac_divisor) * Math.pow(2, exp)); } } // Negative subnormals and -0 for (let sub = max_sub; sub >= min_sub; sub--) { callback(-(sub / sub_divisor) * Math.pow(2, -1022)); } // +0 and positive subnormals for (let sub = min_sub; sub <= max_sub; sub++) { callback((sub / sub_divisor) * Math.pow(2, -1022)); } // Start from just past +0 and move up to the biggest numbers for (let exp = max_exp; exp <= max_exp; exp++) { for (let frac = min_frac; frac <= max_frac; frac++) { callback((1.0 + frac / frac_divisor) * Math.pow(2, exp)); } } callback(Infinity); } iterate_all_floats(function(f) { // Convert to binary for display let floats = new Float64Array(1); let bytes = new Uint8Array(floats.buffer); let str = ''; floats[0] = f; for (let i = 3; i >= 0; i--) { let b = bytes[i]; for (let bit = 7; bit >= 0; bit--) { let val = (b >> bit) & 1; str += val; } } console.log(str, f); });
Enjoy!