Borislav Stanimirov
Borislav Stanimirov

Reputation: 1659

Converting double to string in .NET isn't as precise as C++?

The following C++ program expectedly outputs 0.300000000000000040000:

cout << setprecision(40) << (0.1 + 0.2) << endl;

However the following C# code:

System.Console.WriteLine("{0:F40}", 0.1+0.2);

... unexpetedly outputs 0.3000000000000000000000000000000000000000, while it (expectedly) evaluates 0.1+0.2 == 0.3 as False.

Where is the '4' and how can I output it?

Upvotes: 3

Views: 504

Answers (2)

Jeppe Stig Nielsen
Jeppe Stig Nielsen

Reputation: 61992

What do you get if you say

System.Console.WriteLine("{0:R}", 0.1+0.2);

A format string like "F40" will only add zeros to the end of the string. It will not give you extra precision compared to just "G". On the other hand, "R", will reveal two extra digits (or one if the last of the two digits extra is 0) if (and only if) this is necessary to distinguish the number from a number closer to the string from "G".

Addition: To get a better understanding of how the format strings work in .NET, try running the following code:

double a = BitConverter.ToDouble(new byte[] { 49, 51, 51, 51, 51, 51, 211, 63, }, 0);
double b = BitConverter.ToDouble(new byte[] { 50, 51, 51, 51, 51, 51, 211, 63, }, 0);
double c = BitConverter.ToDouble(new byte[] { 51, 51, 51, 51, 51, 51, 211, 63, }, 0);
double d = BitConverter.ToDouble(new byte[] { 52, 51, 51, 51, 51, 51, 211, 63, }, 0);
double e = BitConverter.ToDouble(new byte[] { 53, 51, 51, 51, 51, 51, 211, 63, }, 0);

Console.WriteLine("using G:");
Console.WriteLine(a.ToString());
Console.WriteLine(b.ToString());
Console.WriteLine(c.ToString());
Console.WriteLine(d.ToString());
Console.WriteLine(e.ToString());
Console.WriteLine("using F40:");
Console.WriteLine(a.ToString("F40"));
Console.WriteLine(b.ToString("F40"));
Console.WriteLine(c.ToString("F40"));
Console.WriteLine(d.ToString("F40"));
Console.WriteLine(e.ToString("F40"));
Console.WriteLine("using R:");
Console.WriteLine(a.ToString("R"));
Console.WriteLine(b.ToString("R"));
Console.WriteLine(c.ToString("R"));
Console.WriteLine(d.ToString("R"));
Console.WriteLine(e.ToString("R"));

Here, a, b, c, d, and e are "neighbors" as System.Doubles which is evident from the byte arrays. You should see that the "R" format string gives extra digits only in case of a, b, and d, e. For c, no extra digits are needed, but it is clear that if one were to write c with 17 figures, the last two of the 17 wouldn't be 00 (see also Jon Skeet's answer for the full decimal expansions which the methods built into .NET won't give you easily).

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1502296

It's not clear whether you'd want exactly the 4 followed by zeroes, but I have some code which will allow you to print out the exact decimal value of any double.

So as a test app:

using System;

class Test
{
    static void Main(string[] args)
    {
        double d1 = 0.1;        
        double d2 = 0.2;
        Console.WriteLine(DoubleConverter.ToExactString(d1 + d2));
        Console.WriteLine(DoubleConverter.ToExactString(0.3));
    }
}

Results:

0.3000000000000000444089209850062616169452667236328125
0.299999999999999988897769753748434595763683319091796875

I suspect that the built-in .NET formatters refuse to give you the "4" on the grounds that at that point the digits can't be "trusted" so to speak. They're just noise related to which value happens to be closest to the value you were really aiming for.

From the docs for System.Double:

By default, a Double value contains 15 decimal digits of precision, although a maximum of 17 digits is maintained internally.

Upvotes: 6

Related Questions