我正在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
。
答案 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)
来强制存储。
摘自谜:
[...]如果未打开编译器优化,则输出将不同。当它开启时,我会变得真实。关闭时,我会得到错误和真实的消息。