在 C# 中将浮点数转换为十进制。为什么 (decimal)0.1F == 0.1M 不是因为四舍五入而为假?

Cast float to decimal in C#. Why is (decimal)0.1F == 0.1M not false because of rounding?

如果我在 C# 中评估以下内容,它会产生 true:

(decimal)0.1F == 0.1M

为什么转换为浮点数再返回十进制不会引入任何舍入错误?

观察到的行为的原因是 Microsoft 的 C# 实现仅使用七位十进制数字将 float 转换为 decimal

Microsoft 的 C# 实现使用 .NET。当 .NET 将单精度浮点数转换为十进制数时,it produces at most seven significant digits,使用舍入到最近的方法舍入任何残差。

源文本0.1F变为单精度值0.100000001490116119384765625。将其转换为具有七位有效数字的十进制时,结果正好是 0.1。因此,在 Microsoft 的 C# 中,(decimal) 0.1F 产生 0.1,因此 (decimal) 0.1F == 0.1M 为真。

我们可以将其与非 Microsoft 实现 Mono C# 进行比较。可以使用在线编译器 here。其中,Console.WriteLine((decimal)0.1F); 打印“0.100000001490116”,(decimal)0.1F == 0.1M 计算结果为 false。将 float 转换为 decimal.

时,Mono C# 似乎产生了超过七位数字

Microsoft’s C# documentation for explicit conversions 表示“当您将 floatdouble 转换为 decimal 时,源值将转换为十进制表示并四舍五入为最接近的 28 位数字如果需要小数位。”我会将其解释为 float 的真实值 0.100000001490116119384765625 准确转换为 decimal(因为它需要少于 28 位数字),但显然情况并非如此。

我们可以进一步证实这一点,并通过将 float 转换为 double 然后再转换为 decimal 来说明发生了什么。 Microsoft’s C# converts double to decimal using 15 significant digits. 如果我们将0.1F 转换为double,值不会改变,因为double 可以准确表示每个float 值。所以 (double) 0.1F0.1F 具有完全相同的值,0.100000001490116119384765625。但是,现在,当它转换为decimal时,会产生15位数字。在 Microsoft C# 实现中,Console.WriteLine((decimal)(double) 0.1F); 打印“0.100000001490116”,(decimal)(double) 0.1F == 0.1M 计算结果为 false。