Search code examples
floating-pointbinaryprecisionfloating-accuracy

What are two numbers of 16 decimal digits precision that map to the same double-precision float?


It is said that any decimal number expressed with 15 digits of precision within the range covered by double-precision floats can be uniquely identified with a particular float. But, that if we include more digits of precision (i.e. 16), we may see that two or more decimal numbers correspond to the same float. See https://www.exploringbinary.com/decimal-precision-of-binary-floating-point-numbers/ for more details.

Could someone please provide me with an example of two number with 16 decimal digits precision that map to the same double-precision float?


Solution

  • Let us try large 16 decimal digit integers of the form 9 xxx xxx xxx xxx xxx:

    #include <stdio.h>
    
    int main() {
      //unsigned long long x0 = 9000000000000000;
      unsigned long long x0 = 1uLL << 53; // 9,007,199,254,740,992
      unsigned long long x1 = 9999999999999999;
      unsigned long long same = 0;
      for (unsigned long long x = x0; x <= x1; x++) {
        double f0 = (double) x;
        double f1 = (double) (x + 1);
        if (f0 == f1) {
          if (same++ == 0) {
            printf("%llu (0x%llX) %llu (0x%llX) both value the value of %f\n", //
                x, x, x + 1, x + 1, f0);
            break;
          }
        }
      }
      printf("Repeats = %llu\n", same);
    }
    

    We rapidly find

        9007199254740992 (0x20000000000000) 9007199254740993 (0x20000000000001) both value the value of 9007199254740992.000000
        Repeats = 1
    

    9007199254740993 (0x20000000000001) is a 54-binary digit value. Common double can only exactly encode up to 53-significant binary digit values.


    Another way to look at it pigeon hole principle.

    Given common double encoding of 52 binary digits per each power-of-2. Between [0.5 ... 1.0), there are 252 or 4,503,599,627,370,496 different double values. Yet in that range there are 5,000,000,000,000,000 different 16 digit decimal values of the form 0.add ddd ddd ddd ddd d (a = [5...9], d = [0-9]), so there is not enough distinct double values to map uniquely to all the 16 decimal digit values of that range. Some decimal values will map to the same double.

    #include <string.h>
    #include <stdio.h>
    
    int main() {
      //                  1234567890123456
      long long x1 =      9999999999999999; // 0x23 86F2 6FC0 FFFF
      char prior[40] = "0.9999999999999999";
      for (long long x = x1; --x > 0; ) {
        char buf[40];
        sprintf(buf, "0.%16lld", x);
        double value = atof(buf);
        if (value == atof(prior)) {
          printf("%s %s both have value %.20g\n", prior, buf, value);
          break;
        }
        strcpy(prior, buf);
      }
      printf("Done\n");
    }
    
    0.9999999999999995 0.9999999999999994 both have value 0.99999999999999944489
    Done