2013-07-07 36 views
4

我有两段小小的代码。在我看来,他们应该得到相同的字符串,但他们不这样做:为什么具有相同值的两位小数格式不同

(1.23M * 100M).ToString() 

结果:

123,00 

(123M).ToString() 

结果:

123 

我的问题很简单:can som ebody向我解释为什么这种(​​奇怪的?)行为发生?

回答

3

它们是两个不同的值,按位。与double不同,decimal不会自动标准化 - 它看起来像保留了在某一点上有两位小数位的信息。你可以看到完全一样的差,而没有乘法:

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

的文档有些含糊(从我所看到的)究竟是如何进行操作的上decimal值的结果,在多少位小数的条款被保留。 (我也不会感到惊讶地得知,它的标准的地方...)

+1

有关于此的文档,但不幸的是,实际行为并不100%符合规范。 –

4

decimal类型是由10倍。从文档缩放整数代表了decimal

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

使用GetBits可以看到123.00M被表示为十分之一万二千三百而123M是10分之123。

编辑

我参加了一个简单的程序,演示功能的问题:

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 

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

相关问题