Почему gcc -ffast-math отключает правильный результат isnan() и isinf()?

Я понимаю, что используя flag разрешает небезопасные математические операции и отключает сигнализацию NaN. Однако я ожидал, что функции и по-прежнему смогут возвращать правильные результаты, а они этого не делают.

Вот пример:

Файл test_isnan.c:

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

int main(void){

  /* Produce a NaN */
  const float my_nan = sqrtf(-1.f);
  /* Produce an inf */
  const float my_inf = 1.f/0.f;

  printf("This should be a NaN: %.6e\n", my_nan);
  printf("This should be inf: %.6e\n", my_inf);

  if (isnan(my_nan)) {
    printf("Caugth the nan!\n");
  } else {
    printf("isnan failed?\n");
  }

  if (isinf(my_inf)) {
    printf("Caugth the inf!\n");
  } else {
    printf("isinf failed?\n");
  }
}

Теперь скомпилируем и запустим программу без -ffast-math:

      $ gcc test_isnan.c -lm -o test_isnan.o && ./test_isnan.o
This should be a NaN: -nan
This should be inf: inf
Caugth the nan!
Caugth the inf!

Но с этим:

      $ gcc test_isnan.c -lm -o test_isnan.o -ffast-math && ./test_isnan.o
This should be a NaN: -nan
This should be inf: inf
isnan failed?
isinf failed?

Так почему бы не isnan() а также isinf() поймать эти nanпесок infс? Что мне не хватает?

Если это может быть актуально, вот мой gcc версия:

      gcc (Spack GCC) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

2 ответа

Из https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html:

-ffast-math
Устанавливает параметры -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only , -fno-rounding-math, -fno-signaling-nans, -fcx-limited-range и - fexcess-precision = быстро.

Где:

-ffinite-math-only
Разрешить оптимизацию арифметики с плавающей запятой, предполагающую, что аргументы и результаты не являются NaN или +-Infs.

В тот момент, когда вы нарушите это предположение, вы не сможете ожидать, что эти функции будут работать.

Я понимаю, что вы надеялись, что этот параметр оптимизирует все другие операции, при этом обеспечивая правильный результат для этих двух функций, но это просто не так, как это работает. Я не думаю, что есть способ решить эту проблему. Может быть, вы можете взглянуть на Clang, но я не ожидаю, что он будет другим.

-ffast-math

Устанавливает параметры ... -ffinite-math-only ...

-ffinite-math-only - только математика

Разрешить оптимизацию для арифметики с плавающей запятой, предполагающую, что аргументы и результаты не являются NaN или +-Infs.

Компилятор оптимизирует код, чтобы:

        printf("This should be a NaN: %.6e\n", sqrtf(-1.f));
  printf("This should be inf: %.6e\n", 1.f/0.f);
  printf("isnan failed?\n");
  printf("isinf failed?\n");

потому что компилятор знает, что выражения не могут возвращать nan или inf.

Другие вопросы по тегам