我能否在运行时让gcc告诉我计算结果是否为NaN或inf?

19

有没有一种方法可以告诉gcc在运行时对导致计算结果为NaN(-)inf的计算抛出类似于除以零一样的SIGFPE信号?

我尝试了-fsignaling-nans标志,但似乎没有用。


1
“-fsignaling-nans” 是运行时而非编译时的。 - LiraNuna
2个回答

25
几乎所有产生NaN的浮点操作或数学库函数,如果其输入不是NaN,则应该发出“无效操作”浮点异常信号;同样,从有限输入产生无穷大的计算通常会发出“除以零”或“溢出”浮点异常信号。因此,您需要一种将这些异常转换为SIGFPE的方法。
我怀疑答案高度依赖于系统,因为控制浮点陷阱和标志可能由平台C库而非gcc本身提供。但以下代码适用于Linux,它使用fenv.h中的feenableexcept函数。_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)来触发异常。


6
在MinGW 4.8.1(Win32的GCC)中,我发现feenableexcept未定义。解决方法是使用Win32平台的_controlfp,代码如下:
#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
}

这在MinGW 4.6.2上似乎无法工作('_clearfp()'在此范围内未声明) - Antonello

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接