在 C# 中,10m * 0.1m 等于 1m 吗?

Does 10m * 0.1m equal 1m in C#?

代码片段

decimal one1 = 10m * 0.1m;
decimal one2 = 10m / 10m;
Console.WriteLine($"{one1}, {one2}, {one1 == one2}");

产生输出:

1.0, 1, True

为什么第一个数字打印有小数点而第二个数字没有。如果答案在于小数类型不具备完全表示0.1的精度,那么为什么等于运算符return为真?

浮点数是一个复杂的概念,由 3 个独立的部分组成,它们存储您认为是数字的信息。

此外,编译器和计算机体系结构如何处理浮点数也不明显。一般来说,这些类型的数字有一些非常奇怪的怪癖;他们如何存储精度;它们可以处理哪些数字,以及编译器和 CPU 如何用它们进行数学运算。

但是,您获得不同值的原因实际上取决于为该数字存储的内容。实际上,它们在内存中的 位和字节 并不相同。相同的数字可以以多种不同的方式存储,并且可以通过不同类型的计算得出(如您所示)。

一起来看看

decimal one1 = 10m * 0.1m;
decimal one2 = 10m / 10m;

int[] bits = decimal.GetBits(one1);

Console.WriteLine("{0,31} {1,10:X8}{2,10:X8}{3,10:X8}{4,10:X8}", one1, bits[3], bits[2], bits[1], bits[0]);

int[] bits2 = decimal.GetBits(one2);

Console.WriteLine("{0,31} {1,10:X8}{2,10:X8}{3,10:X8}{4,10:X8}", one2, bits2[3], bits2[2], bits2[1], bits2[0]);

输出

                        1.0   00010000  00000000  00000000  0000000A
                          1   00000000  00000000  00000000  00000001

如您所见,它们实际上具有明显不同的二进制布局,这意味着表示相同事物的不同尾数和比例因子。

至于调用 ToString() 时额外的 0,编译器知道重要的零,它们是组成数字的一部分,并根据它们的比例保留。

幸运的是,CLR 体系结构 足够聪明,可以区分它们。