是否可以仅针对某些特定的 C++11 代码段 {activate|de-activate} SIGFPE 生成?

Is it possible to {activate|de-activate} SIGFPE generation only for some specific C++11 code segments?

我正在 Linux 上用 C++11 编写路径追踪器,用于光传输的数值模拟,我正在使用

#include <fenv.h>
...
feenableexcept( FE_INVALID   | 
                FE_DIVBYZERO | 
                FE_OVERFLOW  | 
                FE_UNDERFLOW );

为了捕获和调试在执行过程中最终可能出现的任何数字错误。

在代码中的某个时刻,我必须计算光线(线段)与轴对齐边界框 (AABB) 的交点。对于这个计算,我使用了一个非常优化和强大的 ray-box intersection algorithm,它依赖于 IEEE 754 标准中描述的一些特殊值(例如 NaN 和 inf)的生成。显然,我对捕获由这个射线盒相交例程专门生成的浮点异常不感兴趣。

因此,我的问题是:

  1. 是否可以仅针对代码的某些部分(即射线盒相交代码部分)停用浮点异常信号 (SIGFPE) 的生成?
  2. 我们在计算模拟的时候非常关心 表现。在可以抑制异常的情况下 仅针对特定代码部分发出信号,可以在 编译时间(即 instrumenting/de-instrumenting 代码在其 一代,这样我们就可以避免昂贵的函数调用)?

感谢您的帮助!

更新

可以通过使用 feenableexceptfedisableexcept 函数调用来 instrument/deinstrument 编码(实际上,我发布这个问题是因为我不知道 fedisableexcept, 只有 feenableexcept... 真丢人!)。例如:

#include <fenv.h>

int main() {
    float a = 1.0f;

    fedisableexcept(FE_DIVBYZERO);   // disable div by zero catching

    // generates an inf that **won't be** catched
    float c = a / 0.0f;

    feenableexcept(FE_DIVBYZERO);   // enable div by zero catching

    // generates an inf that **will be** catched
    float d = a / 2.0f;

    return 0
}

标准 C++ 不提供任何方式来在编译时标记代码是否应该 运行 启用或禁用浮点捕获。事实上,标准并不要求支持操纵浮点环境,因此实现是否具有它完全取决于实现。超出标准 C++ 的任何答案都取决于您使用的特定硬件和软件,但您尚未报告该信息。

在典型的处理器上,启用和禁用浮点陷阱是通过更改处理器控制寄存器来实现的。您不需要函数调用来执行此操作,但正如您在问题中所建议的那样,函数调用并不昂贵。实际指令可能会消耗时间,因为它可能需要处理器串行化指令执行。 (现代处理器可能有数百条指令同时执行——一些被解码,一些等待处理器内的一个子单元,一些在计算的不同阶段,一些等待将它们的结果写入通用寄存器,等等。当改变一个控制寄存器,处理器可能必须等待所有当前正在执行的指令完成,然后更改寄存器,然后开始执行新指令。)如果您的硬件以这种方式运行,则无法绕过它。 (使用这种常见的硬件,如果不实际执行 运行-time 指令来更改控制寄存器,就不可能将代码编译为 运行 有或没有陷阱。)

您可以通过批处理路径跟踪计算来减少时间成本,因此它们是成组执行的,只需对浮点控制寄存器进行两项更改(一项用于关闭陷阱,一项用于打开陷阱) ) 对于整个组。