nhtrnm
nhtrnm

Reputation: 1617

Is C# Console.WriteLine(double) writing this variable with a full precision?

By "full precision" I mean that there won't be a case where the right result differs from the one I've calculated with my C# program.

I've checked this by running the same tests under a C# and C++ (without using cout.precision()). I'm sure the 2 variants of my program under C# and C++ act similarly on the same tests.

Sample code on C#.

double a;
//...code...
Console.WriteLine(a.ToString(CultureInfo.InvariantCulture));

The same but on C++.

double a;
//...code...
cout << a << endl;

Actually my C++ program without cout.precision() failed and C# with nothing but Console.WriteLine() passed.

I know that this happens because my C++ program truncates the number somehow (maybe magically) and precision is lost. But does passing all the tests mean that C# always prints a doulbe variable with full precision?

Upvotes: 2

Views: 4009

Answers (3)

millimoose
millimoose

Reputation: 39990

Both C++ and C# store floating point numbers as binary fractions. Not all numbers that have a 64-bit representation in base 2 have a reasonably-long representation in base 10. Some rounding will necessarily happen often when converting from a double to, say, a 15-digit decimal.

The reason you're seeing a difference is that the two languages make different default precision choices for converting base 2 to base 10 when printing. (Choices you can customize by printing with an output precision that will round off where you want it.)

Upvotes: 3

phoog
phoog

Reputation: 43066

The exact decimal representation of a double value can go to dozens of places, so the answer in that respect is "no". There is a round-trip format that guarantees enough precision to give a 1-to-1 correspondence between finite numeric decimal strings and finite numeric binary doubles (I don't know how it handles NaNs and infinities), but ToString doesn't use that format unless you specify it ("R"), so the answer in that respect is no, too.

In fact, if you use this overload, you get a result formatted according to the "G" format specifier (see Double.ToString Method (IFormatProvider)).

For information about all the standard specifiers, see Standard Numeric Format Strings.

Jon Skeet has a class that converts doubles to their (possibly very long) exact decimal representations; the associated article is here: http://csharpindepth.com/Articles/General/FloatingPoint.aspx; the class itself is here: http://www.yoda.arachsys.com/csharp/DoubleConverter.cs

Upvotes: 1

Nicholas Carey
Nicholas Carey

Reputation: 74365

If you format your double with the "R" format specifier, you get a "round-trip" representation. See http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx#RFormatString for details. Usage:

string s = someDoubleValue.ToString("R");

The default format specifier, if none is specified, is "G" (General), which "converts a number to the most compact of either fixed-point or scientific notation, depending on the type of the number and whether a precision specifier is present." See http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx#GFormatString for details. If no precision specificer is supplied, double gets 15 digits of precision, so using "G" offers the possibility of a loss of precision.

Upvotes: 5

Related Questions