4

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

(1.23M * 100M).ToString()

结果是:

123,00

(123M).ToString()   

结果是:

123

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

4

2 回答 2

4

decimal类型由一个按 10 倍缩放的整数表示。从文档中decimal

缩放因子还保留 Decimal 数字中的任何尾随零。尾随零不会影响算术或比较运算中的 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

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

于 2013-07-07T20:41:51.130 回答
3

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

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

decimal就保留了多少小数位而言,文档有点不清楚(从我所见)关于值操作的结果是如何执行的。(得知它在某处被标准化,我不会感到惊讶......)

于 2013-07-07T20:37:30.597 回答