在数值应用中,我想知道计算完成后是否发生浮点异常。默认情况下,浮点除法和无效操作将被默默忽略。
我的尝试是启用我关心的 FPE,通过设置标志来处理 SIGFPE,然后再次禁用它们以允许继续执行:
#include <fenv.h>
#include <signal.h>
#include <stdio.h>
int caught = 0;
struct sigaction old_sa;
/* (2) */ fenv_t fenv_hold;
void sighandler()
{
caught = 1;
printf("Caught in handler, disabling\n");
/* (1) */ fedisableexcept(FE_ALL_EXCEPT);
/* (2) */ feholdexcept(&fenv_hold);
sigaction(SIGFPE, &old_sa, NULL);
}
int main(void)
{
struct sigaction sa;
volatile double a=1, b=0;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = sighandler;
sigaction(SIGFPE, &sa, &old_sa);
feenableexcept(FE_DIVBYZERO);
printf("Dividing by zero..\n");
a/=b;
printf("Continuing\n");
}
我采取了两种方法,第一种方法标有
(1)
,第二种方法标有(2)
。它们都没有按预期工作。
输出:
Dividing by zero..
Caught in handler, disabling
Floating point exception (core dumped)
预期输出:
Dividing by zero..
Caught in handler, disabling
Continuing
如果您只是想知道计算完成后是否发生浮点异常,那么您不应该使用信号,因为它们的开销很高。相反,请使用浮点异常标志,这些标志在正常执行期间由处理器快速设置。 (但是,访问它们可能会对性能产生一些影响。)
请参阅
<fenv.h>
上的 C 标准。简而言之:
#include <fenv.h>
。#pragma STDC FENV_ACCESS on
。#pragma STDC FENV_ACCESS off
。feclearexcept(FE_ALL_EXCEPT)
清除标志。fetestexcept(exceptions)
来测试标志。 exceptions
应该是 FE_DIVBYZERO
、FE_INEXACT
、FE_INVALID
、FE_OVERFLOW
和/或 FE_UNDERFLOW
,以及可能的其他实现定义的标志的按位或。请注意,某些 C 实现对访问浮点环境的支持很差。