【问题标题】:Why are two decimals with the same value formatted differently为什么具有相同值的两个小数格式不同
【发布时间】:2013-07-07 20:34:22
【问题描述】:

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

(1.23M * 100M).ToString()

结果:

123,00

(123M).ToString()   

结果:

123

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

【问题讨论】:

    标签: c# decimal tostring


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

      按位,它们是两个不同的值。与double 不同,decimal 不会自动标准化 - 看起来它保留了在某一时刻您有两位小数的信息。不用乘法你可以看到完全相同的差异:

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

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

      【讨论】:

      • 有这方面的文档,但不幸的是实际行为并不 100% 符合规范。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-24
      • 2016-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-26
      相关资源
      最近更新 更多