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

本文关键字:小数 格式 两个 为什么 | 更新日期: 2023-09-27 18:21:18

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

(1.23M * 100M).ToString()

结果在:

123,00

(123M).ToString()   

结果在:

123

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

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

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

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

使用GetBits,可以看到123.00M表示为12300/102,而123M表示为123/100

编辑

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

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

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

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

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

就保留了多少小数位而言,文档中对decimal值的运算结果究竟是如何执行的有些不清楚(从我所看到的情况来看)。(如果我知道它在某个地方是标准化的,我不会感到惊讶…)