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

标签 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 
}

这是什么原因,我该如何预测或避免这些差异?

编辑:将晶圆厂转换为 float 不会改变结果,至少在我的系统上是这样(请参阅 Oli Charlesworth 的评论)。

最佳答案

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

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

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

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

关于c - 同样简单的计算,不同的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24110539/

相关文章:

perl printf : float +1. 2 应打印为 +001.200000

c++ - 通过套接字持续丢失数据(但在使用本地主机连接时不会)

c++ - 如何使用 C++ 成员函数作为 C 框架的回调函数

gcc - CMake:C 编译器无法编译简单的测试程序

linux - 查找海湾合作委员会位置

C++ 异常规范 - 处理无效异常

c# - 在 C# 中将字符串数组转换为 float 组

c++ - float 的整数部分中的 10 进制数字的最大位数是多少

ios - 如何在 build.sh 中正确设置编译器以在 iOS 中构建 VLC

c - newlocale(3) 的掩码位具体是什么意思?