Я включил проверить на нянь в моем тестовом наборе.
Теперь SIGFPE брошен в следующую строку
const double retVal =exp(exponent);
Показатель степени имеет значение приблизительно -4000. Это, конечно, очень близко к нулю, и без проверки нана расчет продолжается с нуля.
Сигнал SIGFPE теперь брошен. Я предполагаю, что это денормальное число (представлен как NAN).
Как я могу различить деление на ноль и показатель степени с очень большим отрицательным значением?
Во втором случае выполнение дальнейших вычислений с нулем работает в моем случае, так как мне не нужно различать +0 и -0.
РЕДАКТИРОВАТЬ:
Я попробовал то, что предложил @ user2079303. Мой код выглядит так
#include <signal.h>
void fpe_handler(int signo, siginfo_t *info, void *context) {
switch(info->si_code) {
case FPE_INTDIV: // division by zero
break;
case FPE_FLTUND: // underflow
break;
// other cases ...
}
}
int main() {
struct sigaction action = {};
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = fpe_handler;
sigaction(SIGFPE, &action, NULL);
const double a = 0.0/0.0;
if (a>0)
return 0;
else
return 1;
}
Это компилирует, но не выдает сигнал или сообщение об ошибке.
Технически, с точки зрения C ++, деление на ноль имеет неопределенное поведение, поэтому не существует стандартного способа его обработки.
В вездесущем стандартном IEEE 754 деление на ноль четко определено и не будет вызывать сигнал. Можно проверить, делено ли ранее выполненное вычисление на ноль, используя <cfenv>
заголовок:
std::feclearexcept(FE_ALL_EXCEPT);
// do calculation here
if(std::fetestexcept(FE_DIVBYZERO)) {
// I was just divided by zero. The sky is falling.
std::abort();
} else if(std::fetestexcept(FE_UNDERFLOW)) {
// I just underflowed. This is my life now.
}
Теперь деление нормального числа с плавающей запятой на ноль не вызывает сигнала, если вы не попросите его использовать feenableexcept
(это расширение GNU; нестандартное).
В стандарте C ++ невозможно различить разные причины SIGFPE. Но есть путь в POSIX стандарт:
void fpe_handler(int signo, siginfo_t *info, void *context)
{
switch(info->si_code) {
case FPE_FLTDIV: // division by zero
break;
case FPE_FLTUND: // underflow
break;
// other cases ...
}
}
// registering
struct sigaction action = {};
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = fpe_handler;
sigaction(SIGFPE, &action, NULL);
Других решений пока нет …