【问题标题】:NAN -> distinguish between a division by zero and an exponent with a very large negative valueNAN -> 区分除以零和具有非常大负值的指数
【发布时间】:2018-02-21 22:27:33
【问题描述】:

我在我的测试套件中包含了check for nan's

现在在下面一行抛出一个 SIGFPE

const double retVal =exp(exponent); 

指数的值大约为 -4000。这当然非常接近于零,如果没有 nan 检查,计算会以零继续进行。

信号 SIGFPE 现在被抛出。我假设这是一个denormal number(表示为 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;
}

这会编译,但不会抛出信号或错误消息。

【问题讨论】:

  • 根据this std::exp referencedouble 参数的有效范围是 -708.4 到 709.8。您的指数显然超出了该范围,也可能超出了long double 的范围。
  • 但也说明If the argument is -∞, +0 is returned。 -inf 和 -708.4 之间的差距是什么?

标签: c++ nan sigfpe


【解决方案1】:

从技术上讲,从 C++ 的角度来看,被零除具有未定义的行为,因此没有标准的方法来处理它。


在无处不在的 IEEE 754 标准中,除以零是明确定义的,不会产生信号。可以使用&lt;cfenv&gt; 标头测试先前执行的计算是否除以零:

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 的不同原因。但是有a way in 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);

【讨论】:

  • @schorsch312 我用可能更相关的东西扩展了我的答案。将普通浮点数除以零不会引发 SIGFPE。
  • 信号处理示例现在也修复了浮点除以零的正确类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-16
  • 1970-01-01
  • 2018-05-12
相关资源
最近更新 更多