比较浮点数的总和[重复]
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),compare1
是 false
而compare2
是 true
。
这是怎么回事?为什么最后两行不同?我认为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) >= 1f
的机器代码似乎没有转换为有限的浮点类型,并且显然使用了更高的位深度,可以观察到数字加起来不等于 1 .
我们可以通过强制转换(float)(a+b)
来强制内存存储。
来自 Enigmativity 的评论:
[...] 如果您打开了编译器优化,输出会有所不同。当它打开时,我变得真实而真实。当它关闭时,我会变得虚假和真实。
【讨论】:
以上是关于比较浮点数的总和[重复]的主要内容,如果未能解决你的问题,请参考以下文章