Search code examples
c#doubledouble-precision

Isn't double able to represent any 2^n number without precision issues? n is natural


This code:

double x = 2.0;
for(int i = 1 ; i<1024 ; i+=i) {
    Console.WriteLine( String.Format( "2^{0} = {1:F0}", i, x ) );
    x*=x;
}

Outputs:

2^1 = 2
2^2 = 4
2^4 = 16
2^8 = 256
2^16 = 65536
2^32 = 4294967296
2^64 = 18446744073709600000
2^128 = 340282366920938000000000000000000000000
2^256 = 115792089237316000000000000000000000000000000000000000000000000000000000000000
2^512 = 13407807929942600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

I thought that double's formula is sign * 2 ^ exponent * fraction; To Illustrate my situation; With setting the fraction to 0.5, the sign to positive, and by setting exponent to any value between -1024 to 1023, I can present any 2^n number that is in the exponent's range; What is wrong with this deduction? Is the formula incomplete?


Solution

  • A double can represent powers of 2 exactly, as demonstrated by the following code (which uses Jon Skeet's DoubleConverter class):

    Console.WriteLine(String.Format("2^{0} = {1}", i, DoubleConverter.ToExactString(x)));
    

    For the F0 specifier, why did the .NET designers choose to round the value off after the 15 most significant decimal digits?

    My guess: Displaying the exact value (such as 18446744073709551616) might imply that the double is precise to all those digits, when in fact a double cannot distinguish between that value and 18446744073709600000. Also, displaying a rounded value is consistent with exponential notation: 1.84467440737096E+19.