使用gcc 4.8.2(Ubuntu 14.04)我得到了不同的结果,同时基本上以相同的方式计算值。根据我测试的系统上的架构(32位/ 64位),还有不同之处。
#include <math.h>
#include <stdio.h>
int main()
{
float h = 0.11f;
float y = 0.11f;
float g = 1.37906f;
float x = 2.916949f;
float result1 = (h * y / fabs(g)) / x;
float result2 = h * y / fabs(g);
result2 /= x;
float result3 = (h * y / g) / x;
printf("%.20f \n", result1); //0.00300796888768672943
printf("%.20f \n", result2); //0.00300796912051737309
printf("%.20f \n", result3); //0.00300796912051737309 on x64
//0.00300796888768672943 on x32
}
原因是什么以及如何预测或避免这些差异?
编辑:将晶圆厂投入浮动并不会改变结果,至少在我的系统上是这样(见Oli Charlesworth的评论)。
答案 0 :(得分:4)
C99标准不是强迫所有C编译器实现像早期Java标准那样的浮点计算的严格标准,而是允许在理想模式下进行一些变化,其中每个操作按顺序完成并根据IEEE进行舍入。 754格式对应浮点类型。
您可以向GCC询问它遵循的浮点计算模型,并且您可以使用命令行选项来更改其行为并使其更具可预测性。 有两种情况:
-std=c99
进行编译。如果没有它(具体来说,没有它所暗示的-fexcess-precision=standard
),浮点计算的确切结果是不可预测的,并且您允许编译器为result1
,result2
生成不同的结果, result3
)。使用-std=c99
时,result1
和result3
的值必须相同。 result2
的值可能不同,因为result2
的中间分配会强制计算该点的值四舍五入为float
。-msse2 -mfpmath=sse
)。在此模式下,fabs
已被fabsf
替换的所有三个计算都应产生相同的结果。这样做的缺点是生成的代码只与过去12年左右生成的处理器兼容(!)答案 1 :(得分:2)
前两个不同,因为fabs
会返回double
。因此,在第一个版本中,除x
除以双精度完成。在第二个版本中,它是以单精度完成的。
答案 2 :(得分:-1)
原因是您使用的float
类型的精度约为6位十进制数
并且结果在前6位有效数字内达成一致。