以下代码在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;
}
答案 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)