浮点代码中的错误,还是gcc?

时间:2011-04-14 08:49:17

标签: c gcc floating-point

以下代码在64位下按预期工作,但在-O2和-O3的32位下失败,预期输出为1.1,在打印1.0的错误系统下。我试图确定这是否是我的代码中的错误(对浮点数如何工作做出一些错误的假设)或在GCC中。如果它在我的代码中,我该怎么做呢?

#include <math.h>
#include <stdio.h>


int f(double x) {
    return isinf(1.0 / x);
}

int m_isinf(double x) {
    return x != 0 && x * 0.5 == x;
}

int g(double x) {
    return m_isinf(1.0 / x);
}

double values[] = {
    5.5e-309,
    -1.0
};

int main() {
    int i;
    for (i = 0; values[i] != -1.0; i++) {
        printf("%d\n", f(values[i]));
        printf("%d\n", g(values[i]));
    }
    return 0;
}

4 个答案:

答案 0 :(得分:3)

可以比类型更精确地评​​估表达式。在32位版本中,编译器可能使用80位长的双精度(在64位中不再使用)来评估x != 0 && x * 0.5 == x

(海湾合作委员会已经知道这些规则存在问题,在不能确定的情况下进行更精确的评估)。

C99中的6.3.1.8/2(C90中的6.2.1.5是等效的):

  

浮动操作数的值和浮动表达式的结果可以是   代表的精度和范围比该类型所要求的更高;类型不是   由此改变

在符合要求的实施中:

int m_isinf(double x) {
    double const half_x = x * 0.5;
    return x != 0 && half_x == x;
}

应该有效。但是gcc bug(http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323查看重复数量)通常会阻止它工作。 bug报告中有一些工作。

答案 1 :(得分:2)

基本上,在浮点数和双打数上使用相等比较是意外行为的可靠方法。

答案 2 :(得分:1)

您可以直接检查该值,如下所示:

#include <math.h>

int isinf(double d) {
  union {
    unsigned long long l;
    double d;
  } u;
  u.d=d;
  return (u.l==0x7FF0000000000000ll?1:u.l==0xFFF0000000000000ll?-1:0);
}

由dietlibc提供

答案 3 :(得分:0)