Oracle® Solaris Studio 12.4: Numerical Computation Guide

Exit Print View

Updated: January 2015
 
 

4.5 Handling Exceptions

Historically, most numerical software has been written without regard to exceptions, and many programmers have become accustomed to environments in which exceptions cause a program to abort immediately. High-quality software packages such as LAPACK are carefully designed to avoid exceptions such as division by zero and invalid operations and to scale their inputs aggressively to preclude overflow and potentially harmful underflow. Neither of these approaches to dealing with exceptions is appropriate in every situation. However, ignoring exceptions can pose problems when you write a program or subroutine that is intended to be used by someone else, for example, who might not have access to the source code. Attempting to avoid all exceptions can require many defensive tests and branches and carry a significant cost. For more information, see Demmel and Li, “Faster Numerical Algorithms via Exception Handling,” IEEE Trans. Comput. 43 (1994), pp. 983–992.

The default exception response, status flags, and optional trapping facility of IEEE arithmetic are intended to provide a third alternative: continuing a computation in the presence of exceptions and either detecting them after the fact or intercepting and handling them as they occur. As described above, ieee_flags or the C99 floating-point environment functions can be used to detect exceptions after the fact, and ieee_handler or fex_set_handling can be used to enable trapping and install a handler to intercept exceptions as they occur. In order to continue the computation, however, the IEEE standard recommends that a trap handler be able to provide a result for the operation that incurred an exception. A SIGFPE handler installed via ieee_handler or fex_set_handling in FEX_SIGNAL mode can accomplish this using the uap parameter supplied to a signal handler by the Solaris operating environment. An FEX_CUSTOM mode handler installed via fex_set_handling can provide a result using the info parameter supplied to such a handler.

Recall that a SIGFPE signal handler can be declared in C as follows:

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

When a SIGFPE signal handler is invoked as a result of a trapped floating-point exception, the uap parameter points to a data structure that contains a copy of the machine's integer and floating-point registers as well as other system-dependent information describing the exception. If the signal handler returns normally, the saved data are restored and the program resumes execution at the point at which the trap was taken. Thus, by accessing and decoding the information in the data structure that describes the exception and possibly modifying the saved data, a SIGFPE handler can substitute a user-supplied value for the result of an exceptional operation and continue computation.

An FEX_CUSTOM mode handler can be declared as follows:

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

When a FEX_CUSTOM handler is invoked, the ex parameter indicates which type of exception occurred (it is one of the values listed in Table 4–4) and the info parameter points to a data structure that contains more information about the exception. Specifically, this structure contains a code representing the arithmetic operation that caused the exception and structures recording the operands, if they are available. It also contains a structure recording the default result that would have been substituted if the exception were not trapped and an integer value holding the bitwise “or” of the exception flags that would have accrued. The handler can modify the latter members of the structure to substitute a different result or change the set of flags that are accrued. (Note that if the handler returns without modifying these data, the program will continue with the default untrapped result and flags just as if the exception were not trapped.)

As an illustration, the following section shows how to substitute a scaled result for an operation that underflows or overflows. See Appendix A, Examples for further examples.