16

I am facing a problem when I try to convert decimal? to string. Scenario is

decimal decimalValue = .1211;
string value = (decimalValue * 100).ToString();

Current Result : value = 12.1100

Expected Result : value = 12.11

Please let me know, what could be reason for this.

Audrius
  • 2,836
  • 1
  • 26
  • 35
Pushkar
  • 275
  • 1
  • 2
  • 9
  • 1
    The reason is probably the system's default numeric format for decimal numbers. – Thorsten Dittmar May 15 '13 at 10:24
  • 2
    Did you want it to display more than two decimal places if they're non-zero? That is, if you had `.12113405` you would want it to appear as `12.113405`? – Chris Sinclair May 15 '13 at 10:26
  • Just what I was thinking: is it just the trailing zeroes, or do you want to always limit by 2 decimals? In the former case, none of the answers provide a good answer. – John Willemse May 15 '13 at 10:31
  • Want to know the reason, why toString() method is adding two extra zero. – Pushkar May 15 '13 at 12:23

7 Answers7

20

Decimal preserves any trailing zeroes in a Decimal number. If you want two decimal places instead:

decimal? decimalValue = .1211m;
string value = ((decimal)(decimalValue * 100)).ToString("#.##")

http://msdn.microsoft.com/en-us/library/0c899ak8.aspx

or

string value = ((decimal)(decimalValue * 100)).ToString("N2")

http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx

From System.Decimal:

A decimal number is a floating-point value that consists of a sign, a numeric value where each digit in the value ranges from 0 to 9, and a scaling factor that indicates the position of a floating decimal point that separates the integral and fractional parts of the numeric value.

The binary representation of a Decimal value consists of a 1-bit sign, a 96-bit integer number, and a scaling factor used to divide the 96-bit integer and specify what portion of it is a decimal fraction. The scaling factor is implicitly the number 10, raised to an exponent ranging from 0 to 28. Therefore, the binary representation of a Decimal value is of the form, ((-296 to 296) / 10(0 to 28)), where -296-1 is equal to MinValue, and 296-1 is equal to MaxValue.

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

Remarks:

  1. the decimal multiplication needs to be casted to decimal, because Nullable<decimal>.ToString has no format provider
  2. as Chris pointed out you need to handle the case that the Nullable<decimal> is null. One way is using the Null-Coalescing-Operator:

    ((decimal)(decimalValue ?? 0 * 100)).ToString("N2")
    

This article from Jon Skeet is worth reading:

Decimal floating point in .NET (seach for keeping zeroes if you're impatient)

Mason G. Zhwiti
  • 6,444
  • 11
  • 61
  • 97
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • Casting to `decimal` will throw an `InvalidOperationException` with this code, whereas Pushkar's original code would result in an empty string. Possibly not relevant in this case though. – Chris Sinclair May 15 '13 at 10:41
  • Sorry Tim, I meant it will throw when `decimalValue` is `null`. – Chris Sinclair May 15 '13 at 10:45
  • Thanks for replying. I know, it can be solved by specifying the formatter but I want to know why toString() method is adding extra zero. – Pushkar May 15 '13 at 12:09
  • @Pushkar: Have you read my quoted msdn link? _"The scaling factor also preserves any trailing zeroes in a Decimal number....trailing zeroes can be revealed by the ToString method if an appropriate format string is applied"_ Your original decimal has 4 dcimal places, hence `ToString` reveals them. Btw, here's an explanation why it can be useful to remember the number of trailing zeros: http://stackoverflow.com/a/2996821/284240 – Tim Schmelter May 15 '13 at 12:12
6

Since you using Nullable<T> as your decimal, Nullable<T>.ToString() method doesn't have overloading takes parameters that you can use for formatting.

Instead of, you can explicitly cast it to decimal and you can use .ToString() method for formatting.

Just use "0.00" format in your .ToString() method.

decimal? decimalValue = .1211M;
string value = ((decimal)(decimalValue * 100)).ToString("0.00");
Console.WriteLine(value);

Output will be;

12.11

Here is a DEMO.

As an alternative, you can use Nullable<T>.Value without any conversation like;

string value = (decimalValue * 100).Value.ToString("0.00");

Check out for more information from Custom Numeric Format Strings

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
2

Alternatively, you can specify the format "F2", like so: string val = decVal.ToString("F2") as this specifies 2 decimal places.

Davio
  • 4,609
  • 2
  • 31
  • 58
2

Use the fixed-point ("F) format specifier .

   string value = (decimalValue * 100).ToString("F");

The default precision specifier is based on value of NumberFormatInfo.NumberDecimalDigits property which by default has value 2. So if don't specify a digit aftyer "F" , it by default specifies two decimal digits.

F0 - No decimal places
F1 - One decimal place
Mudassir Hasan
  • 28,083
  • 20
  • 99
  • 133
1

In case you do not want to limit to a certain amount of decimal digits:

decimal? decimalValue = .1211;
string value = decimalValue == null 
               ? "0"
               : decimalValue == 0
               ? "0"
               : (decimalValue * 100).ToString().TrimEnd('0');

This will trim any (if any) trailing zeroes of the string and also return "0" if decimalValue is null. If the value is 0 then "0" is returned without trimming.

John Willemse
  • 6,608
  • 7
  • 31
  • 45
0
String.Format("{0:0.00}", decimalValue * 100);

You can use .Format() as an alternative to .ToString("0.00").

emre nevayeshirazi
  • 18,983
  • 12
  • 64
  • 81
0

Since decimal? does not have a ToString(string format) overload, the easiest way is to use String.Format instead which will provide consistent results with the null case for decimalValue as well (resulting in an empty string) when compared to your original code:

string value = String.Format("{0:#.##}", decimalValue * 100);

But there are some other considerations for other numbers that you weren't clear on.

If you have a number that does not produce a value greater than 0, does it show a leading zero? That is, for 0.001211, does it display as 0.12 or .12? If you want the leading zero, use this instead (notice the change from #.## to 0.##):

string value = String.Format("{0:0.##}", decimalValue * 100);

If you have more than 2 significant decimal places, do you want those displayed? So if you had .12113405 would it display as 12.113405? If so use:

string value = String.Format("{0:#.############}", decimalValue * 100);

(honestly, I think there must be a better formatting string than that, especially as it only supports 12 decimal places)

And of course if you want both leading zeros and multiple decimal places, just combine the two above:

string value = String.Format("{0:0.############}", decimalValue * 100);
Chris Sinclair
  • 22,858
  • 3
  • 52
  • 93