比较浮点数

时间:2020-03-01 02:33:10

标签: c# visual-studio unity3d

我正在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)中,compare1false,而compare2true

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

2 个答案:

答案 0 :(得分:0)

您遇到了一个非常常见的数值精度错误,称为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个有效数字。

答案 1 :(得分:0)

来自this answer

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

我相信sum = a + b会生成一条指令,将结果存储为最大64位浮点数。

由于编译器的优化,(a + b) >= 1f的机器代码似乎没有转换为有限的浮点类型,并且显然使用了更高的位深度,由此可以看出,这些数字并没有相加到1。

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

摘自谜:

[...]如果未打开编译器优化,则输出将不同。当它开启时,我会变得真实。关闭时,我会得到错误和真实的消息。