10m * 0.1m 是否等于 C# 中的 1m?

Phi*_*gan 3 c# precision decimal

代码片段

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

产生输出:

1.0, 1, True
Run Code Online (Sandbox Code Playgroud)

为什么第一个数字带有小数点而第二个数字没有。如果答案在于十进制类型没有完全表示的精度0.1,那么为什么相等运算符返回 true?

AAA*_*ddd 6

浮点数是一个复杂的概念,由 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]);
Run Code Online (Sandbox Code Playgroud)

输出

                        1.0   00010000  00000000  00000000  0000000A
                          1   00000000  00000000  00000000  00000001
Run Code Online (Sandbox Code Playgroud)

如您所见,它们实际上具有显着不同的二进制布局,这意味着代表同一事物的不同尾数和缩放因子。

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

幸运的是,CLR架构足够聪明,可以分辨出差异。

  • “小数”除以十和乘以十的结果是精确的(因此在这种情况下两个值的结果相等)与运气无关——这就是该类型的设计目的,并且编译器和 CLR 根据其规范运行。 (2认同)