英特尔编译器无法处理小数的绝对值

Intel compilers cannot handle absolute value of small number

gcc 7.2.0 相比,使用 intel 2018 编译我的代码时,我遇到了一些非常奇怪的舍入错误。我只是在考虑获取极小数字的绝对值:

#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

是什么导致我的英特尔编译器版本有如此巨大的差异?

错误的功能或错误的语言

"gcc 7.2.0" 的输出符合预期,因为 OP 是用 C++ 编译的

"intel/2018" 输出与强制 C 编译一致。

对于 C,abs(numa)numa 转换为值为 0 的 int,下面是 未定义的行为(UB ) 因为 "%.17g" 期望 double 而不是 int.

// In C UB:       vvvvv------vvvvvvvvv
printf("abs(numa) %.17g \n", abs(numa));

利用 "abs(numa) 2.0410903428666442e-314" 的 UB 输出,我们可以做一些取证。

典型的2.0410903428666442e-314在binary

00000000 00000000 00000000 00000000 11110110 00111101 01001110 00101110

这与某些通过 32 位 int 0 然后 printf() 检索它以及预期的其他后续垃圾的 C 编译是一致的 double.

作为 UB,此结果可能会不时变化,如果有输出的话,但它是问题的良好指标:用 C++ 编译或更改为 fabs() ()在 C++ 和 C 中取 double 的绝对值。


OP 在调试浮点问题时使用 "%g"(或 "%e")的一些荣誉。 "%f"

的信息量更大