Matthew Layton
Matthew Layton

Reputation: 42340

Why does Double.ToString("#") and BigInteger.ToString() produce different results for the same value?

Consider the following code:

double d = double.MaxValue;
BigInteger bi = new(d);
Console.WriteLine(d.ToString("#"));
Console.WriteLine(bi.ToString());

This yields the following result:

179769313486232000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368

The BigInteger representation of this value contains seemingly random numbers, whilst the double representation contains 294 trailing zeros. Both are the same length.

Why is this, and what are those seemingly random numbers?

Upvotes: 1

Views: 67

Answers (1)

Jeremy Lakeman
Jeremy Lakeman

Reputation: 11138

If you look at the implementation of BigInteger(double), you'll see that the internal representation is stored in an int[] in base 2. The value from the double is packed into the last 3 elements of this _bits array;

// Populate the uints.
_bits = new uint[cu + 2];
_bits[cu + 1] = (uint)(man >> (cbit + kcbitUint));
_bits[cu] = unchecked((uint)(man >> cbit));
if (cbit > 0)
    _bits[cu - 1] = unchecked((uint)man) << (kcbitUint - cbit);
_sign = sign;

All the other _bits[0..cu -1] elements will be initialised to zero. Giving a final value of the form x * 2^k, not x * 10^k. Any large value of k may look like random noise when converted to base 10.

But in base 16, the answer is obvious;

new BigInteger(double.MaxValue).ToString("X") == "0FFFFFFFFFFFFF800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"

It's double.MaxValue.ToString("#") that is rounding the significant digits in base 10.

Upvotes: 3

Related Questions