Могу ли я сделать так, чтобы gcc сообщал мне, когда вычисление приводит к NaN или inf во время выполнения? - PullRequest
17 голосов
/ 31 мая 2010

Есть ли способ сказать gcc выбросить SIGFPE или что-то подобное в ответ на вычисление, которое приводит к NaN или (-)inf во время выполнения, как это было бы для деления на ноль?

Я пробовал флаг -fsignaling-nans, который, похоже, не помогает.

Ответы [ 2 ]

21 голосов
/ 01 июня 2010

Почти любая операция с плавающей точкой или математическая библиотечная функция, которая генерирует NaN из не-NaN-входов, также должны сигнализировать об исключении с плавающей точкой «недопустимая операция»; аналогично, вычисление, которое производит бесконечность из конечных входных данных, обычно сигнализирует об исключении с плавающей точкой «деление на ноль» или «переполнение». Таким образом, вы хотите каким-то образом превратить эти исключения в SIGFPE.

Я подозреваю, что ответ будет сильно зависеть от системы, поскольку управление ловушками и флагами с плавающей точкой, скорее всего, будет предоставлено библиотекой платформы C, а не самим gcc. Но вот пример, который работает для меня, на Linux. Используется функция feenableexcept из fenv.h. Определение _GNU_SOURCE необходимо для объявления этой функции.

#define _GNU_SOURCE
#include <fenv.h>

int main(void) {
    double x, y, z;
    feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);

    x = 1e300;
    y = 1e300;
    z = x * y; /* should cause an FPE */

    return 0;
}

Предостережение: я думаю, что с некоторыми установками возможно, что исключение фактически не генерируется до тех пор, пока следующая операция с плавающей запятой после той, которая (в теории) должна была вызвать ее, поэтому иногда нужна операция с плавающей точкой без операции (например, умножение на 1,0), чтобы вызвать исключение.

4 голосов
/ 07 января 2014

На MinGW 4.8.1 (GCC для Win32) я вижу, что feenableexcept не определен. Обходной путь должен использовать _controlfp платформы Win32, таким образом:

#undef __STRICT_ANSI__ // _controlfp is a non-standard function documented in MSDN
#include <float.h>
#include <stdio.h>

int main()
{
   _clearfp();
   unsigned unused_current_word = 0;
   // clearing the bits unmasks (throws) the exception
   _controlfp_s(&unused_current_word, 0, _EM_OVERFLOW | _EM_ZERODIVIDE);  // _controlfp_s is the secure version of _controlfp

   float num = 1.0f, den = 0.0f;
   float quo = num / den;
   printf("%.8f\n", quo);    // the control should never reach here, due to the exception thrown above
}
...