【问题标题】:Cast float to decimal in C#. Why is (decimal)0.1F == 0.1M not false because of rounding?在 C# 中将浮点数转换为十进制。为什么(十进制)0.1F == 0.1M 因为四舍五入而不是假的?
【发布时间】:2018-11-05 22:13:06
【问题描述】:

如果我在 C# 中评估以下内容,则结果为 true:

(decimal)0.1F == 0.1M

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

【问题讨论】:

  • (decimal)somethingF 并不总是等于 somethingM - 由于浮点的工作方式。然而,这并不意味着它们将永远相等。
  • 这感觉像是一个 XY 问题 - meta.stackexchange.com/questions/66377/what-is-the-xy-problem。为什么这对你很重要?
  • @mjwills 因为浮点数中的 0.1 实际上是 0.100000001490116119384765625,所以我希望它们不相等。
  • @Aae 那你为什么使用浮点数而不是双精度数?
  • 此外,它们对单个值的行为方式并不能代表它们对任意值的行为方式。

标签: c# floating-point rounding-error


【解决方案1】:

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

Microsoft 的 C# 实现使用 .NET。当 .NET 将单精度浮点数转换为十进制时,it produces at most seven significant digits,使用四舍五入对任何余数进行四舍五入。

源文本0.1F 变为单精度值 0.100000001490116119384765625。当它转换为具有七位有效数字的十进制时,结果正好是 0.1。因此,在微软的 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。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多