22

Is there a way to get a string showing the exact value of a double, with all the decimal places needed to represent its precise value in base 10?

For example (via Jon Skeet and Tony the Pony), when you type

double d = 0.3;

the actual value of d is exactly

0.299999999999999988897769753748434595763683319091796875

Every binary floating-point value (ignoring things like infinity and NaN) will resolve to a terminating decimal value. So with enough digits of precision in the output (55 in this case), you can always take whatever is in a double and show its exact value in decimal. And being able to show people the exact value would be really useful when there's a need to explain the oddities of floating-point arithmetic. But is there a way to do this in C#?

I've tried all of the standard numeric format strings, both with and without precision specified, and nothing gives the exact value. A few highlights:

  • d.ToString("n55") outputs 0.3 followed by 54 zeroes -- it does its usual "round to what you probably want to see" and then tacks more zeroes on the end. Same thing if I use a custom format string of 0.00000...
  • d.ToString("r") gives you a value with enough precision that if you parse it you'll get the same bit pattern you started with -- but in this case it just outputs 0.3. (This would be more useful if I was dealing with the result of a calculation, rather than a constant.)
  • d.ToString("e55") outputs 2.9999999999999999000000000000000000000000000000000000000e-001 -- some of the precision, but not all of it like I'm looking for.

Is there some format string I missed, or some other library function, or NuGet package or other library, that is able to convert a double to a string with full precision?

Joe White
  • 94,807
  • 60
  • 220
  • 330
  • 2
    You could use John Skeet's DoubleConverter class: http://www.yoda.arachsys.com/csharp/DoubleConverter.cs See this answer: http://stackoverflow.com/a/1658420/1445661 – mao47 Mar 05 '14 at 14:24
  • The question I have to ask is: What do you need this for? If you explain what you want it for perhaps we can give you a better approach at getting it. – Scott Chamberlain Mar 05 '14 at 14:25
  • 2
    The data past the 16th significant digit is needed to exactly represent the binary value of the double. That binary value follows some combination of language and IEEE floating point standard rules. Seeing those digits is important for understanding floating point behavior and rounding. In Java, I would do it by converting to BigDecimal, whose default toString produces its exact value. – Patricia Shanahan Mar 05 '14 at 14:25
  • 1
    Seeing mao47's comment, [the linked question](http://stackoverflow.com/questions/1421520/formatting-doubles-for-output-in-c-sharp) is kind of a duplicate and the answer is spot on for this question. There is no way to do it natively in .NET, you have to do like Jon Skeet's library and get the bits from BitConverter and parse out the double by hand. – Scott Chamberlain Mar 05 '14 at 14:28
  • @HenkHolterman The duplicate question wants to output a double with full precession with formatting like `{0:F20}`, how is that different then what this question asks other than the other question stopped at 20 and this question extends it to 55? – Scott Chamberlain Mar 05 '14 at 14:32
  • 1
    It is a meaningless string of digits that no human would ever want to look at. You can get a much shorter one with BitConverter.DoubleToInt64Bits().ToString() – Hans Passant Mar 05 '14 at 14:42
  • I also have an article on how to do this, similar to Jon's. Jon rolls his own big decimal class, I use the rational class from the solver foundation library. See http://ericlippert.com/2011/02/17/looking-inside-a-double/ – Eric Lippert Mar 05 '14 at 15:55
  • @PatriciaShanahan +1, that's how we do it in Squeak Smalltalk too (aFloat asFraction printShowingMaxDecimalPlaces: 1074) – aka.nice Mar 05 '14 at 22:43

2 Answers2

-2

You could try using # placeholders if you want to suppress trailing zeroes, and avoid scientific notation. Though you'll need a lot of them for very small numbers, e.g.:

Console.WriteLine(double.Epsilon.ToString("0.########....###"));
Joe
  • 122,218
  • 32
  • 205
  • 338
-3

I believe you can do this, based on what you want to accomplish with the display:

Consider this:

Double myDouble = 10/3;

myDouble.ToString("G17");

Your output will be:

3.3333333333333335

See this link for why: http://msdn.microsoft.com/en-us/library/kfsatb94(v=vs.110).aspx

By default, the return value only contains 15 digits of precision although a maximum of 17 digits is maintained internally. If the value of this instance has greater than 15 digits, ToString returns PositiveInfinitySymbol or NegativeInfinitySymbol instead of the expected number. If you require more precision, specify format with the "G17" format specification, which always returns 17 digits of precision, or "R", which returns 15 digits if the number can be represented with that precision or 17 digits if the number can only be represented with maximum precision.

You can also do:

myDouble.ToString("n16");

That will discard the 16th and 17th noise digits, and return the following:

3.3333333333333300

If you're looking to display the actual variable value as a number, you'll likely want to use "G17". If you're trying to display a numerical value being used in a calculation with high precision, you'll want to use "n16".

ravibhagw
  • 1,740
  • 17
  • 28
  • This is not what the OP wants, I fell in to the same mental thinking too at first and made a comment similar to your answer but then deleted it. – Scott Chamberlain Mar 05 '14 at 14:24