NAN — & gt; различают деление на ноль и показатель степени с очень большим отрицательным значением

Я включил проверить на нянь в моем тестовом наборе.

Теперь 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;
}

Это компилирует, но не выдает сигнал или сообщение об ошибке.

4

Решение

Технически, с точки зрения 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);
3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]