在 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 表示“当您将 float
或 double
转换为 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.1F
与 0.1F
具有完全相同的值,0.100000001490116119384765625。但是,现在,当它转换为decimal
时,会产生15位数字。在 Microsoft C# 实现中,Console.WriteLine((decimal)(double) 0.1F);
打印“0.100000001490116”,(decimal)(double) 0.1F == 0.1M
计算结果为 false。
如果我在 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
.
Microsoft’s C# documentation for explicit conversions 表示“当您将 float
或 double
转换为 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.1F
与 0.1F
具有完全相同的值,0.100000001490116119384765625。但是,现在,当它转换为decimal
时,会产生15位数字。在 Microsoft C# 实现中,Console.WriteLine((decimal)(double) 0.1F);
打印“0.100000001490116”,(decimal)(double) 0.1F == 0.1M
计算结果为 false。