为什么具有相同值的两个小数的格式不同

时间:2013-07-07 20:34:23

标签: c# decimal tostring

我有两小段代码。在我看来,它们应该产生相同的字符串,但它们不会:

(1.23M * 100M).ToString()

结果:

123,00

(123M).ToString()   

结果:

123

我非常简单的问题是:有人可以解释为什么会发生这种(奇怪的?)行为吗?

2 个答案:

答案 0 :(得分:4)

decimal类型由一个按因子10缩放的整数表示。来自decimal的文档:

  

缩放因子还会保留十进制数中的任何尾随零。尾随零不会影响算术或比较运算中的十进制数的值。但是,如果应用了适当的格式字符串,ToString方法可能会显示尾随零。

使用GetBits,您可以看到123.00M表示为12300/10 2 ,而123M为123/10 0

修改

我采用了一个简单的程序来解释这个问题:

class Program
{

    static void Main(string[] args)
    {
        Console.WriteLine((1.23M * 100M).ToString());
        Console.WriteLine((123M).ToString());
    }

}

我看了一下生成的IL:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       51 (0x33)
  .maxstack  6
  .locals init ([0] valuetype [mscorlib]System.Decimal CS$0$0000)
  IL_0000:  nop
  IL_0001:  ldc.i4     0x300c
  IL_0006:  ldc.i4.0
  IL_0007:  ldc.i4.0
  IL_0008:  ldc.i4.0
  IL_0009:  ldc.i4.2
  IL_000a:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32,
                                                                     int32,
                                                                     int32,
                                                                     bool,
                                                                     uint8)
  IL_000f:  stloc.0
  IL_0010:  ldloca.s   CS$0$0000
  IL_0012:  call       instance string [mscorlib]System.Decimal::ToString()
  IL_0017:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_001c:  nop
  IL_001d:  ldc.i4.s   123
  IL_001f:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32)
  IL_0024:  stloc.0
  IL_0025:  ldloca.s   CS$0$0000
  IL_0027:  call       instance string [mscorlib]System.Decimal::ToString()
  IL_002c:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0031:  nop
  IL_0032:  ret
} // end of method Program::Main

我们可以看到编译器实际上优化了乘法,并为第一种情况插入了一个构造单个十进制实例的调用。这两个实例使用不同的表示。它们基本上就是我上面所描述的。

答案 1 :(得分:3)

它们是两个不同的值,按位。与double不同,decimal不会自动规范化 - 看起来它保留了一点上有两位小数的信息。你可以在没有乘法的情况下看到完全相同的差异:

Console.WriteLine(123m)
Console.WriteLine(123.00m);

根据保留的小数位数,对于decimal值的操作结果到底是如何执行的,文档有点不清楚(从我所看到的)。 (我不会惊讶地发现它已在某处标准化了......)