2

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

4

3 回答 3

5

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

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

  1. 如果要生成 387 代码,请使用最近的 GCC(4.8 应该没问题)和-std=c99. 没有它(具体来说,没有-fexcess-precision=standard它所暗示的),浮点计算的确切结果是不可预测的,并且您允许编译器为result1,result2result3) 生成不同的结果。对于,和-std=c99的值必须相同。的值可以不同,因为中间赋值强制计算的那个点的值被舍入到 a 。result1result3result2result2float
  2. 停止生成 387 代码,改为生成 SSE2 代码(选项-msse2 -mfpmath=sse)。在这种模式下,所有三个fabs被替换的计算都fabsf应该产生相同的结果。这样做的缺点是生成的代码仅与过去 12 年左右生产的处理器兼容(!)

更多信息:post1post2,从打算为 C 程序编写静态分析器的人的角度编写,该分析器可以精确预测浮点计算的结果。

于 2014-06-08T22:04:34.857 回答
2

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

于 2014-06-08T20:36:29.000 回答
-1

原因是您使用float的类型精度约为 6 位小数。
结果在前 6 位有效数字内一致。

于 2014-06-08T22:18:30.700 回答