Oracle® Solaris Studio 12.4:数值计算指南

退出打印视图

更新时间: 2015 年 1 月
 
 

4.5 处理异常

在以前,大多数数值软件在编写时都未考虑异常,许多编程人员经常遇到异常导致程序立即中止的环境。现在,一些高质量的软件包(如 LAPACK)经过了仔细设计,从而避免了异常(如除以零和无效运算)并主动设置其输入范围以排除溢出和可能有害的下溢。在处理异常的这些方法中,没有一种能够适合所有情况。但是,当一个人编写的程序或子例程将要由他人(可能是没有源代码访问权限的人)使用时,忽略异常可能会导致问题。尝试避免所有异常可能需要许多防御性测试和分支,并且还会产生巨大成本有关更多信息,请参见 Demmel 和 Li 合著的《Faster Numerical Algorithms via Exception Handling》,这篇文章发表在《IEEE Trans.Comput.》的第 43 期(1994),位于第 983–992 页。

IEEE 算法的缺省异常响应、状态标志和可选的捕获功能旨在提供第三个替代功能:在异常存在的情况下继续计算,并在事后检测它们或者在它们发生时拦截和处理它们。如上所述,ieee_flags 或 C99 浮点环境函数可用于在事后检测异常,ieee_handlerfex_set_handling 可用于启用捕获并安装要在异常发生时拦截它们的处理程序。但是,为了继续计算,IEEE 标准推荐使用能够为导致了异常的运算提供结果的陷阱处理程序。在 FEX_SIGNAL 模式中通过 ieee_handlerfex_set_handling 安装的 SIGFPE 处理程序可使用 uap 参数(由 Solaris 操作系统提供给信号处理程序)完成上述操作。通过 fex_set_handling 安装的 FEX_CUSTOM 模式处理程序可使用提供给类似处理程序的 info 参数提供结果。

请记住,在 C 中,可按如下方式声明 SIGFPE 信号处理程序:

#include <siginfo.h>
#include <ucontext.h>
 
void handler(int sig, siginfo_t *sip, ucontext_t *uap)
{
    ...
}

当由于捕获到浮点异常而调用 SIGFPE 信号处理程序时,uap 参数将指向一个数据结构,该结构中包含计算机的整数和浮点寄存器的副本,以及其他描述该异常的、依赖系统的信息。如果该信号处理程序正常返回,则所保存的数据将被恢复,该程序将从捕获点继续执行。因此,通过访问描述异常的数据结构中的信息、对该信息进行解码并(可能)修改所保存的数据,SIGFPE 处理程序可将用户提供的值替换为异常运算的结果并继续计算。

可按如下方式声明 FEX_CUSTOM 模式处理程序:

#include <fenv.h>
 
void handler(int ex, fex_info_t *info)
{
    ...
}

FEX_CUSTOM 处理程序被调用时,ex 参数指出所发生的异常的类型(该类型是列在Table 4–4 中的某个值),info 参数指向一个包含更多异常信息的数据结构。特别是,该结构中包含一个代码(代表导致了该异常的算术运算)和多个用来记录操作数(如果它们可用的话)的结构。该结构中还包含一个用来记录缺省结果(如果异常未被捕获,这些结果将被替换)的结构和一个整数值(保存已发生的异常标志的按位“或”)。此处理程序可以修改该结构后面的成员,以便替换另一个结果或者更改已发生标志的设置。(请注意,如果该处理程序在不修改这些数据的情况下返回,则该程序将继续显示缺省的未捕获结果和标志,就好像异常未被捕获一样。)

下一节举例说明了如何替换下溢或溢出运算的缩放结果。有关更多示例,请参见Appendix A, 示例