【问题标题】:Comparing the sum of floats [duplicate]比较浮点数的总和[重复]
【发布时间】:2020-06-13 17:23:47
【问题描述】:

我在 Unity 中运行此代码(使用 .Net 4.x 的 Mono 后端)

float a = 0.42434249394294f;
float b = 1 - a;
float sum = a + b;
bool compare1 = (a + b) >= 1f;
bool compare2 = sum >= 1f;

在调试中(使用 Visual Studio),compare1falsecompare2true

这是怎么回事?为什么最后两行不同?我认为sum == a + b

【问题讨论】:

  • 他们是花车。阅读浮点数学的本质。大多数浮点数是它们打算表示的数字的近似值。永远不要检查浮点数或双精度数是否相等。在这里,您正在检查 >= 1f,但实际上,您正在检查 == 1f
  • 我有浮点运算的理论知识。但我原以为最后一行会产生相同的结果。我会澄清这个问题。
  • @dodgy_coder 我找到了this:“浮点中间结果通常在寄存器中使用 80 位精度,但在内存中仅使用 64 位”
  • 如果您可以链接到另一个副本,那就太好了。甚至我链接的答案 (stackoverflow.com/a/328644/6879283) 也比当前的副本清晰得多。

标签: c# visual-studio unity3d


【解决方案1】:

您遇到了一个非常常见的数值精度错误,称为round-off error。在对浮点值求和时,您需要包含误差容限。这种错误是所有编程语言中的浮点数学运算所固有的。

您的代码应更改为如下所示:

const float errorTolerance = 0.000001f;
float target1 = a + b;
float target2 = sum;
bool compare1 = Math.Abs(target1 - 1f) <= errorTolerance;
bool compare2 = Math.Abs(target2 - 1f) <= errorTolerance;

还要注意 c# 中的浮点数,它是单精度浮点数,精度只有 6-7 位有效数字。

【讨论】:

    【解决方案2】:

    来自this answer

    2.) 浮点中间结果通常在寄存器中使用 80 位精度,但在内存中仅使用 64 位。

    我相信,sum = a + b 会生成一条指令以将结果存储在内存中,作为最多 64 位的浮点数。

    由于编译器优化,(a + b) &gt;= 1f 的机器代码似乎没有转换为有限的浮点类型,并且显然使用了更高的位深度,可以观察到数字加起来不等于 1 .

    我们可以通过强制转换(float)(a+b)来强制内存存储。

    来自 Enigmativity 的评论:

    [...] 如果您打开了编译器优化,输出会有所不同。当它打开时,我变得真实而真实。当它关闭时,我会变得虚假和真实。

    【讨论】:

      猜你喜欢
      • 2011-10-24
      • 2023-04-05
      • 2011-08-20
      • 1970-01-01
      • 2012-10-26
      • 1970-01-01
      • 2012-07-17
      相关资源
      最近更新 更多