2012-12-10 28 views
1
var numberFormat = new NumberFormatInfo(); 
numberFormat.NumberDecimalSeparator = "."; 
numberFormat.NumberDecimalDigits = 2; 

decimal a = 10.00M; 
decimal b = 10M; 

Console.WriteLine(a.ToString(numberFormat)); 
Console.WriteLine(b.ToString(numberFormat)); 
Console.WriteLine(a == b ? "True": "False"); 

在控制台: 10.00 真奇数小数类型的行为

它为什么不一样?更重要的是,不管变量如何初始化,我如何调用ToString()来确保输出相同。

+0

您期待什么输出? 10,10,是真的吗? –

+0

嗯,我有点希望10.00 10.00是真的,但至少应该清楚numberFormat是错误的,如果它是10 10真实的。这只是让我感到困惑(因为我的实际代码并不那么简单,需要一些时间才能弄清楚为什么数字格式可以保留一位小数,但错误的是另一位数) – Damir

+0

备注:bool实现了一个可用的'ToString',所以'Console 。WriteLine(a == b);'将打印与您的示例中相同的内容。 –

回答

2

NumberDecimalDigits属性用于与"F""N"标准格式字符串,而不是ToString方法称为无格式字符串。

您可以使用:

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

试试这个:

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

输出将始终小数点后2例。更多的例子在这里:

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

+0

但它并不总是有小数点分隔符。 – Guffa

+0

无关紧要数字有小数分隔符或不是,输出将总是有2个小数点。如果你尝试'Console.WriteLine(String.Format(“{0:0.00}”,10M));'你会看到输出是'10.00' –

+1

你错过了这一点。在数字格式中指定的OP小数点分隔符应该是一个句点。如果您未使用数字格式,则小数点分隔符将改为默认文化中指定的那个。当我尝试这些代码时,我发现输出是'10,00'。 – Guffa

4

如何使它输出始终已回答了,这个问题,但在这里就是为什么它们输出不同的摆在首位:

一个decimal值包含在内部,领域一个尺度和一个系数。在10M的情况下,编码的值具有10的系数和标度为0:

10M = 10 * 10^0 

10.00M的情况下,编码的值具有1000的系数,为2的比例:

10.00M = 1000 * 10^(-2) 

您可以排序的方法通过在内存中的检查值看到:

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") + " "); 
    } 
} 

输出

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是10进制,并了0x3e8是1000十六进制)

此行为是在C#规范的2.4.4.3节中概述:

的实数由M或后缀m是十进制的类型。例如,文字1m,1.5m,1e10m和123.456M都是十进制类型。该字面值通过采用精确值转换为十进制值,并且如有必要,使用银行家舍入(第4.1.7节)将其舍入到最接近的可表示值。 除非值被舍入或值为零(在后一种情况下符号和比例将为0),否则将保留文字中任何明显的比例。因此,文字2.900米将被解析为符号0,系数2900和刻度3的小数。

+0

有趣,谢谢你的努力。然而,这解释了它们的不同之处,并不是ToString为什么关心它们在记忆中的表现方式。不应该对原始类型的ToString提供某种类型的保证,提供逻辑上相同的输入,它会返回相同的输出?或者这是由设计(ToString的行为,而不是小数)? – Damir