为什么两个具有相同值的小数格式不同
本文关键字:小数 格式 两个 为什么 | 更新日期: 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
值的运算结果究竟是如何执行的有些不清楚(从我所看到的情况来看)。(如果我知道它在某个地方是标准化的,我不会感到惊讶…)