Odd decimal type behavior for ToString(IFormatProvider)

风格不统一 提交于 2019-12-02 06:01:01

The NumberDecimalDigits property is used with the "F" and "N" standard format strings, not the ToString method called without a format string.

You can use:

Console.WriteLine(a.ToString("N", numberFormat));

The question of how to make it output consistently has been answered, but here is why they output differently in the first place:

A decimal value contains, internally, fields for a scale and a coefficient. In the case of 10M, the value encoded has a coefficient of 10 and a scale of 0:

10M = 10 * 10^0

In the case of 10.00M, the value encoded has a coefficient of 1000 and a scale of 2:

10.00M = 1000 * 10^(-2)

You can sort of see this by inspecting the values in-memory:

unsafe
{
    fixed (decimal* array = new decimal[2])
    {
        array[0] = 10M;
        array[1] = 10.00M;
        byte* ptr = (byte*)array;

        Console.Write("10M:    ");
        for (int i = 0; i < 16; i++)
            Console.Write(ptr[i].ToString("X2") + " ");

        Console.WriteLine("");

        Console.Write("10.00M: ");
        for (int i = 16; i < 32; i++)
            Console.Write(ptr[i].ToString("X2") + " ");
    }
}

Outputs

10M:    00 00 00 00 00 00 00 00 0A 00 00 00 00 00 00 00
10.00M: 00 00 02 00 00 00 00 00 E8 03 00 00 00 00 00 00

(0xA is 10 in hex, and 0x3E8 is 1000 in hex)

This behaviour is outlined in section 2.4.4.3 of the C# spec:

A real literal suffixed by M or m is of type decimal. For example, the literals 1m, 1.5m, 1e10m, and 123.456M are all of type decimal. This literal is converted to a decimal value by taking the exact value, and, if necessary, rounding to the nearest representable value using banker's rounding (§4.1.7). Any scale apparent in the literal is preserved unless the value is rounded or the value is zero (in which latter case the sign and scale will be 0). Hence, the literal 2.900m will be parsed to form the decimal with sign 0, coefficient 2900, and scale 3.

Try this:

Console.WriteLine(String.Format("{0:0.00}", a)); 
Console.WriteLine(String.Format("{0:0.00}", b)); 

The output will have always 2 decimal cases. More examples here:

http://www.csharp-examples.net/string-format-double/

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!