Компиляторы Intel не могут обрабатывать абсолютное значение небольшого числа - PullRequest
0 голосов
/ 06 декабря 2018

Я сталкиваюсь с некоторыми очень странными ошибками округления при компиляции моего кода с 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 будет иметь такую ​​огромную разницу?

1 Ответ

0 голосов
/ 07 декабря 2018

Неправильная функция или неправильный язык

Вывод с "gcc 7.2.0" соответствует ожиданиям, поскольку OP скомпилирован с C ++

С выводом "intel / 2018"согласуется с принудительной компиляцией C.

С C abs(numa) преобразует numa в int со значением 0, а ниже неопределенное поведение (UB)поскольку "%.17g" ожидает double, а не int.

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

С выходом UB "abs(numa) 2.0410903428666442e-314" мы можем провести некоторые экспертизы.

Типичные 2.0410903428666442e-314 в двоичном равно

00000000 00000000 00000000 00000000 11110110 00111101 01001110 00101110

Это согласуется с некоторыми компиляциями C, которые проходят 32-битный int 0, а затем printf() извлек это, наряду с некоторым другим следующим мусором как ожидаемое double.

Как UB, этот результат может время от времени изменяться, если вывод вообще, все же является хорошим индикатором проблемы: Скомпилируйтев C ++ или измените на fabs() ( @ dmuir ), чтобы принять абсолютное значение double в C ++ и C.


Некоторые благодарности OP за использование "%g" (или "%e") при отладке с плавающей запятой.Гораздо более информативный "%f"

...