同样简单的计算,不同的结果

时间:2014-06-08 20:32:27

标签: c gcc floating-point gcc4.8

使用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的评论)。

3 个答案:

答案 0 :(得分:4)

C99标准不是强迫所有C编译器实现像早期Java标准那样的浮点计算的严格标准,而是允许在理想模式下进行一些变化,其中每个操作按顺序完成并根据IEEE进行舍入。 754格式对应浮点类型。

您可以向GCC询问它遵循的浮点计算模型,并且您可以使用命令行选项来更改其行为并使其更具可预测性。 有两种情况:

  1. 如果您要生成387代码,请使用最近的GCC(4.8应该没问题)和-std=c99进行编译。如果没有它(具体来说,没有它所暗示的-fexcess-precision=standard),浮点计算的确切结果是不可预测的,并且您允许编译器为result1result2生成不同的结果, result3)。使用-std=c99时,result1result3的值必须相同。 result2的值可能不同,因为result2的中间分配会强制计算该点的值四舍五入为float
  2. 停止生成387代码,改为生成SSE2代码(选项-msse2 -mfpmath=sse)。在此模式下,fabs已被fabsf替换的所有三个计算都应产生相同的结果。这样做的缺点是生成的代码只与过去12年左右生成的处理器兼容(!)
  3. 更多信息:post1post2,是从打算为C程序编写静态分析器的人的角度编写的,它精确地预测了浮点计算的结果。

答案 1 :(得分:2)

前两个不同,因为fabs会返回double。因此,在第一个版本中,除x除以双精度完成。在第二个版本中,它是以单精度完成的。

答案 2 :(得分:-1)

原因是您使用的float类型的精度约为6位十进制数 并且结果在前6位有效数字内达成一致。