The smallest number that is infinite

1 hour ago 2

In software, we represent real numbers as binary floating-point numbers. Effectively, we represent real numbers as a fixed-precision integer (the significand) multiplied by a power of two. Thus we do not represent exactly the number ‘pi’, but we get a very close approximation: 3.141592653589793115997963468544185161590576171875.  The first 16 digits are exact.

You can represent the approximation of pi as 7074237752028440 times 2 to the power -51. It is a bit annoying to represent numbers in this manner, so let us use the hexadecimal float notation.

In the hexadecimal float notation, The number 1 would be 0x1.0 and the number two would be 0x2.0. It works just like the decimal numbers. Except that the value one half would be 0x0.8 and the infinite string 0xffffff…. would be 1.

Let us go back to the number pi. We write the significand as an hexadecimal number, 0x1921fb54442d18 and we insert a period right after the first digit: 0x1.921fb54442d18. It is a number in the range [1,2), specifically 0x1921fb54442d18 times 2 to the power -52.

To get the number pi, we need to multiply by 2, which we do by appending ‘p+1’ at the end: 0x1.921fb54442d18p+1.

Of course, you do not compute any of this by hand. In modern C++, you just do:

std::print("Pi (hex): {:a}\n", std::numbers::pi);

If you are using 64-bit floating point numbers, then you can go from about -1.7976931348623157e+308 to 1.7976931348623157e308 using the exponential notation where 1.79769e308  means 1.79769 times 10 to the power 308. In hexadecimal notation, the largest value is 0x1.fffffffffffffp+1023. The integer value 0x1fffffffffffff is 9007199254740991 and the largest value is 9007199254740991 times 2 to the power 1023-52.

Numbers outside of this range are represented by an infinite value. Indeed, our computers have a notion of infinity. And they know that 1 over infinity is 0. Thus in modern C++, the following would print zero.

double infinity = std::numeric_limits<double>::infinity(); std::print("Zero: {}\n", 1 / infinity);

You might be surprised to find that if you type in a string value that is larger than the maximal value that can represented, you do not get an error or an infinite value. For example, the number represented by the string 1.7976931348623158e308 is larger than the largest value that can be represented by a floating-point type, but it is not infinite. The following C++ code will print ‘true’:

std::print("{}\n", 1.7976931348623158e308 == std::numeric_limits<double>::max());

So what is the smallest number represented as a string that will map to infinity? Let us go back to the hexadecimal representation.

  1. The second largest value is 0x1.ffffffffffffep+1023
  2. The largest value is 0x1.fffffffffffffp+1023.
  3. The next largest value would be 0x2.0p+1023.
  4. The midpoint between the two is 0x1.fffffffffffff8p+1023.

By default, we always round to the nearest value. Thus all number strings between 0x1.ffffffffffffe8p+1023 and 0x1.fffffffffffff8p+1023 fall to 0x1.fffffffffffffp+1023. If you are right at 0x1.fffffffffffff8p+1023, then we ’round to the nearest even’ value, which is 0x2.0p+1023. Thus the number 0x1.fffffffffffff8p+1023 is right at the border with the infinite values.

In decimal, this value is 179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792.0.

If you type this string as a number constant, many compilers (irrespective of the programming language) will complain and reject it. Any number string just slightly smaller should be fine.

Read Entire Article