比较浮点数的总和[重复]

Posted

技术标签:

【中文标题】比较浮点数的总和[重复]【英文标题】: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 我有浮点运算的理论知识。但我原以为最后一行会产生相同的结果。我会澄清这个问题。 Q: Is floating point math broken? @dodgy_coder 我找到了this:“浮点中间结果通常在寄存器中使用 80 位精度,但在内存中仅使用 64 位” 如果您可以链接到另一个副本,那就太好了。甚至我链接的答案 (***.com/a/328644/6879283) 也比当前的副本清晰得多。 【参考方案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 的评论:

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

【讨论】:

以上是关于比较浮点数的总和[重复]的主要内容,如果未能解决你的问题,请参考以下文章

比较 Unity 中的浮点数

比较c ++中的两个浮点数/双精度数[重复]

汇编中浮点数的总和数组

golang比较浮点数是不是相等

“表达式不可分配”——将浮点数分配为 Xcode 中其他两个浮点数的总和时出现问题?

浮点数的比较