2

Consider the following code:

decimal decimalVal = 4.00M;

double doubleVal = 5.00;

Console.Write(decimalVal);

Console.Write(doubleVal);

Why are the zeroes after the decimal in decimalVal displayed, but those after the decimal in doubleVal are not?

leppie
  • 115,091
  • 17
  • 196
  • 297
Nitin Aggarwal
  • 451
  • 1
  • 7
  • 18
  • 1
    What do you mean "it returns as"? How are you viewing its value? 4 is 4.0 is 4.0000000000, so obviously you are wondering about a specific form of string formatting. – Ed S. Jan 14 '15 at 01:02
  • I searched Google for the exact title of your question. The first hit was http://stackoverflow.com/questions/618535/difference-between-decimal-float-and-double-in-net. Your question is a duplicate of that one. – John Saunders Jan 14 '15 at 01:05
  • John i got more from the post you mentioned in your answer, but i am still not clear why zeroes are not shown on double values? – Nitin Aggarwal Jan 14 '15 at 01:14
  • 2
    `decimal` _must_ preserve the precision of the value it represents. `double` doesn't. When you define a decimal `4` with 3 significant figures, that is exactly what you get. The double `5.00` can be represented with the exact value `5`. How many decimal places it had is not encoded into the value. – Jeff Mercado Jan 14 '15 at 03:32
  • possible duplicate of [String contains trailing zeroes when converted from decimal](http://stackoverflow.com/questions/25372014/string-contains-trailing-zeroes-when-converted-from-decimal) – Raymond Chen Jan 14 '15 at 09:16

1 Answers1

6

The difference you're seeing is due to how Console.Write() was designed.

When you call Console.Write like this:

 Console.Write(decimalVal);

 Console.Write(doubleVal);

Under the covers, it's actually calling ToString() and passing it your current culture, equivalent to this:

 Console.Write(decimalVal.ToString(Thread.CurrentThread.CurrentCulture));

 Console.Write(doubleVal.ToString(Thread.CurrentThread.CurrentCulture));

Those two lines do not specify a format, so the general ("G") format for your culture is used, as noted in the documentation for Double.ToString() and Decimal.ToString().

 Console.Write(decimalVal.ToString("G"));

 Console.Write(doubleVal.ToString("G"));

So what does the "G" format specifier output? Again, from the docs:

The result contains a decimal point if required, and trailing zeros after the decimal point are omitted. If the precision specifier is present and the number of significant digits in the result exceeds the specified precision, the excess trailing digits are removed by rounding.

However, if the number is a Decimal and the precision specifier is omitted ... trailing zeros are preserved.

(my emphasis added)

So the end result is that Console.Write() outputs...

  • Your double value without trailing zeroes.

  • Your decimal value with trailing zeroes.

At first, I chalked the difference up to "developer's choice", but then Raymond Chen and Jeff Mercado both commented on the underlying reason:

It's because decimal remembers how much precision it has. 4.00M and 4.0M are not the same. (Although they compare equal.) Conversion to string reveals the precision. Double does not track precision. ~Raymond

decimal must preserve the precision of the value it represents. double doesn't. When you define a decimal ``4 with 3 significant figures, that is exactly what you get. The double 5.00 can be represented with the exact value 5. How many decimal places it had is not encoded into the value. ~Jeff

Additionally, from the Decimal documentation:

The scaling factor also preserves any trailing zeros in a Decimal number. Trailing zeros do not affect the value of a Decimal number in arithmetic or comparison operations. However, trailing zeros might be revealed by the ToString method if an appropriate format string is applied.

(The "scale factor" is a value that represents the fractional portion of the decimal - the portion after the decimal point.)

What this means is, although 3.0m, 3.00m and 3.000000m are all considered equal when you compare them, the Decimal type stores an appropriate scale factor to ensure the trailing zeroes are not lost.

This does not apply to the Double type, where leading zeroes are not retained. Although, if you had a double and wanted to ensure at least a couple zeroes were displayed, you could specify a format:

Console.Write(doubleVal.ToString("F2"));  // outputs 5.00
Community
  • 1
  • 1
Grant Winney
  • 65,241
  • 13
  • 115
  • 165
  • 1
    It's because decimal remembers how much precision it has. 4.00M and 4.0M are not the same. (Although they compare equal.) Conversion to string reveals the precision. Double does not track precision. – Raymond Chen Jan 14 '15 at 09:19