与intel 2018
相比,使用gcc 7.2.0
编译代码时,我面临一些非常奇怪的舍入错误。我只是在考虑极小的数字的绝对值:
#include <cfloat>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
double numa = -1.3654159537789158e-08;
double numb = -7.0949094162313382e-08;
if (isnan(numa))
printf("numa is nan \n");
if (isnan(numb))
printf("numb is nan \n");
printf("abs(numa) %.17g \n", abs(numa));
printf("abs(numb) %.17g \n", abs(numb));
if ((isnan(numa) || (abs(numa) < DBL_EPSILON)) || (isnan(numb) || (abs(numb) < DBL_EPSILON))) {
printf("x %.17g y %.17g DBL_E %.17g \n", numa, numb, DBL_EPSILON);
}
return 0;
}
以下是使用gcc 7.2.0
编译代码时的输出,这是预期的:
$ ./a.out
abs(numa) 1.3654159537789158e-08
abs(numb) 7.0949094162313382e-08
但这与intel/2018
的故事不同:
$ ./a.out
abs(numa) 2.0410903428666442e-314
abs(numb) 2.0410903428666442e-314
x -1.3654159537789158e-08 y -7.0949094162313382e-08 DBL_E 2.2204460492503131e-16
什么会导致我的Intel编译器版本有如此大的差异?
答案 0 :(得分:1)
功能错误或语言错误
与“ gcc 7.2.0”一起输出是预期的,因为OP是使用C ++编译的
使用“ intel / 2018”,输出与强制C编译一致。
使用C,abs(numa)
将numa
转换为值为0的int
,以下是 undefined behavior (UB),其值为{{1 }}期望"%.17g"
而不是double
。
int
使用UB输出// In C UB: vvvvv------vvvvvvvvv
printf("abs(numa) %.17g \n", abs(numa));
,我们可以进行一些取证。
binary中的典型2.0410903428666442e-314是
00000000 00000000 00000000 00000000 11110110 00111101 01001110 00101110
这与某些C编译通过32位"abs(numa) 2.0410903428666442e-314"
,然后int 0
检索此代码以及随后的其他垃圾作为预期的printf()
一致。
作为UB,此结果有时可能会有所不同(如果有输出的话),但仍然可以很好地说明问题:使用C ++编译或更改为double
(@dmuir) C ++和C中fabs()
的绝对值。
在调试浮点问题时,使用double
(或"%g"
)对OP很有帮助。 "%e"