fharreau
fharreau

Reputation: 2337

String.Format with infinite precision and at least 2 decimal digit

I am developing an application for some guys very picky about numerical accuracy (they are dealing among others with accounting and very accurate telecom variables). For this reason I am using the decimal type everywhere, because the float and double types are not suitable (do not hesitate to redirect me to an existing better datatype).

My problem comes when I need to format those numbers. The requirement is to display as many decimal digit as needed but at least 2 and also to use a group separator for thousands.

For example:

Value       Formatted
1                1.00
1000         1,000.00
1.5              1.50
1000.355    1,000.355
0.000035     0.000035

So I went the MSDN looking for numeric string formats. I found this useful resource Standard Numeric Formats but none of my tries works as expected (N, N2, F, F2, G, G2, etc, I tried various combinations even when I didn't believe in them ^^ - I even try some F2# for fun).

My conclusion is there is not a built-in format to do what I want. Right?

So I checked out the next chapter Custom Numeric Formats. But I couldn't find a combination that suit my needs. So I went to SO and find a lots of question about that (1, 2, and so on).

These questions let me fear that the only solution is this one: #,##0.00####### with as many trailing # as I need precision.

Am I right?

I guess that with 12 #, my guys won't find any accuracy issue, but I might have missed the magical format I need?

Upvotes: 2

Views: 500

Answers (3)

Hackerman
Hackerman

Reputation: 12305

I created a little function: it formats the number based on how many decimal places it has:

    public static void Main()
    {
        decimal theValue;
        theValue = 0.000035M;
        Console.WriteLine(theFormat(theValue));
        theValue = 1.5M;
        Console.WriteLine(theFormat(theValue));
        theValue = 1;
        Console.WriteLine(theFormat(theValue));                 
    }
    public static decimal theFormat(decimal theValue){
        int count = BitConverter.GetBytes(decimal.GetBits(theValue)[3])[2];
        return count > 1?theValue:Convert.ToDecimal(string.Format("{0:F2}", theValue));
    }

This, produces the following output:

0.000035
1.50
1.00

Upvotes: 1

Sach
Sach

Reputation: 10393

This is probably what you're looking for:

static string FormatNumber(string input)
{
    var dec = decimal.Parse(input);
    var bits = decimal.GetBits(dec);
    var prec = bits[3] >> 16 & 255;
    if (prec < 2)
        prec = 2;
    return dec.ToString("N" + prec);
}

When you call it, do a ToString() on decimals, and convert the result back to decimal if needed.

I tried your example numbers, and the result:

enter image description here

Based on this SO answer.

Upvotes: 2

Kostya
Kostya

Reputation: 849

If you want a total control over formatting you can implement your own IFormatProvider for decimals. Inside of it you can use StringBuilder and do anything you need with no restrictions of string.Format().

Upvotes: 0

Related Questions