捕获安静NaN

15

我有一个应用程序,在其中一些组件偶尔会在大型数据流中插入qNaN,这将使整个处理失效(对包含单个qNaN的向量进行FFT会导致所有输出为qNaN)。现在我想在其中捕捉该组件,并找出它为什么这样做。

为此,我需要在调试期间使所有NaN值都是信号类型。在使用执行32位代码的x64 CPU的情况下,是否有方法可以做到这一点?


1
不完全是重复,但有很多细节。https://dev59.com/YHRB5IYBdhLWcg3wn4YL - user7116
另一个有详细信息的问题:https://dev59.com/LnE95IYBdhLWcg3wlu4g - user7116
1
可能是重复的问题:如何在C++中跟踪NaN - legends2k
2个回答

23

如果您想在调试期间将所有NaN、溢出和零除法设置为信号,请注意以下方法。

对于gcc:

#include <fenv.h>

#ifndef NDEBUG
feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
#endif

对于Visual Studio(未经测试):

#include <float.h>

#ifndef NDEBUG
_clearfp();
_controlfp(_controlfp(0, 0) & ~(_EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW),
           _MCW_EM);
#endif

参考资料:Microsoft, gcc


这些函数可以捕获由浮点操作(溢出、零除、无效操作)产生的NaN,或被用作某些浮点操作输入的sNaN。它们无法捕获用作浮点操作输入的qNaN。对于这样的qNaN,唯一的方法就是逐个检查每个值(请参见Luchian Grigore的答案)。

因此,如果插入qNaN的组件与您要捕获的程序在同一个程序中,或者如果该组件在单独的程序中,但您拥有其源代码,请使用feenableexcept()/_controlfp()启用FP异常。否则,请使用isnan()(C++11)或x != x检查传入数据流中的每个值。


你把这个放在实现文件里吗? - Luchian Grigore
@LuchianGrigore,是的,只需从main()中调用此函数即可。 - Evgeny Kluev
嗯,仍然没有出现异常,但是我接受了它,因为它让我在调试方面走上了正确的轨道。 - Simon Richter
如果你真的需要一个异常,有一种方法。但非常缓慢和复杂。你可以编写驱动程序(内核模块),在“CR0”控制寄存器中设置“EM”标志,并在每个FP操作上获取异常。然后检查qNaN并在内核模式下执行操作。 - Evgeny Kluev
或者您可以尝试修补387仿真代码以简化此任务。 - Evgeny Kluev

7

我怀疑没有一种方法可以在整个内存中设置数据断点来捕获所有的NaN。

我会寻找插入到vector中的代码,并在那里测试是否为NaN

if ( x != x )
    assert(!"NaN detected");

4
你为什么没有将条件放在 assert 语句中呢? - Lightness Races in Orbit
@LightnessRacesinOrbit 我确实考虑过这个问题,但是像这样对于未经训练的人来说更易读。 - Luchian Grigore
这是一个宝贵的机会来训练你的眼力。 - John McFarlane

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