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...
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