【问题标题】:Trapping quiet NaN捕获安静的 NaN
【发布时间】:2012-03-08 14:16:19
【问题描述】:

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

为此,我需要在调试期间以某种方式使所有 NaN 发出信号。有没有办法让 x64 CPU 执行 32 位代码?

【问题讨论】:

标签: c++ debugging x86 floating-point


【解决方案1】:

如果你想在调试过程中让所有的 NaN、溢出和 zerodivides 信号,都是可以的。

对于 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

参考:Microsoftgcc


这些函数允许捕获由浮点运算(溢出、零除、无效运算)产生的 NaN,或用作某些浮点运算的输入的 sNaN。它们不允许捕获 qNaN,用作浮点运算的输入。对于此类 qNaN,找到它们的唯一方法是单独检查每个值(请参阅 Luchian Grigore 的回答)。

所以如果插入 qNaN 的组件在同一个程序中,你想捕获它,或者如果这个组件在单独的程序中,但你有它的源代码,只需使用 feenableexcept()/ 启用 FP 异常_controlfp()。否则,使用isnan() (C++11) 或x != x 检查传入数据流中的每个值。

【讨论】:

  • 你把这个放到实现文件里了吗?
  • @LuchianGrigore,是的,只需从 main() 调用它。
  • 嗯,仍然没有得到异常,但接受,因为它使我在调试方面走上了正轨。
  • 如果你真的需要例外,有办法。但是非常缓慢和复杂。您可以编写驱动程序(内核模块),在“CR0”控制寄存器中设置“EM”标志,并在每次 FP 操作时获取异常。然后检查 qNaN 并在内核模式下执行操作。
  • 或者您可以尝试修补 387 仿真代码以简化此任务。
【解决方案2】:

我怀疑有没有办法在内存中放置一个数据断点来捕获所有 NaNs

我会寻找插入vector 的代码并在那里测试NaN

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

【讨论】:

  • 您没有将条件放入assert 本身是否有原因?
  • @LightnessRacesinOrbit 我确实考虑过,但对于像这样未经训练的人来说,它更具可读性。
  • 这是训练眼睛的宝贵机会。
猜你喜欢
  • 2012-01-01
  • 1970-01-01
  • 2017-11-15
  • 2021-08-30
  • 2012-09-25
  • 2015-06-19
  • 1970-01-01
  • 2021-06-26
  • 2015-02-25
相关资源
最近更新 更多