IBM Books

User's Guide


Detecting and Trapping Floating-Point Exceptions

As stated earlier, the IEEE standard for floating-point arithmetic defines a number of exception (or error) conditions that might require special care to avoid or recover from. The following sections are intended to help you make your programs work safely in the presence of such exception conditions, while sacrificing the minimum amount of performance.

The floating-point hardware always detects a number of floating-point exception conditions (which the IEEE standard rigorously defines): overflow, underflow, zerodivide, invalid, and inexact.

By default, the only action that occurs is that a status flag is set. The program continues without a problem (although the results from that point on may not be what you expect). If you want to know when an exception occurs, you can arrange for one or more of these exception conditions to generate a signal.

The signal causes a branch to a handler routine. The handler receives information about the type of signal and the state of the program when the signal occurred. It can produce a core dump, display a listing showing where the exception occurred, modify the results of the calculation, or carry out some other processing that you specify.

Both the XL Fortran compiler and the operating system provide facilities for working with floating-point exception conditions. The compiler facilities indicate the presence of exceptions by generating SIGTRAP signals. The operating-system facilities generate SIGFPE signals. Do not mix these different facilities within a single program.

Compiler Features for Trapping Floating-Point Exceptions

To turn on XL Fortran exception trapping, compile the program with the -qflttrap option and some combination of suboptions that includes enable. This option uses trap operations to detect floating-point exceptions, and generates SIGTRAP signals when exceptions occur.

-qflttrap also has suboptions that correspond to the names of the exception conditions. For example, if you are only concerned with handling overflow and underflow exceptions, you could specify something similar to the following:

  xlf95 -qflttrap=overflow:underflow:enable compute_pi.f
You only need enable when you are compiling the main program. However, it is very important, and does not cause any problems if you specify it for other files, so always include it when you use -qflttrap.

An advantage of this approach is that performance impact is relatively low. To further reduce performance impact, you can include the imprecise suboption of the -qflttrap option. This suboption delays any trapping until the program reaches the start or end of a subprogram.

The disadvantages of this approach include the following:

Notes:

  1. If your program depends on floating-point exceptions occurring for particular operations, also specify -qfloat suboptions that include nofold and nohssngl. Otherwise, the compiler might replace an exception-producing calculation with a constant NaN or infinity value, or eliminate an overflow in a single-precision operation.

  2. The suboptions of the -qflttrap option replace an earlier technique that required you to modify your code with calls to the fpsets and fpgets procedures. You no longer require these calls for exception handling if you use the appropriate -qflttrap settings.

    Attention: If your code contains fpsets calls that enable checking for floating-point exceptions, and you do not use the -qflttrap option when compiling the whole program, the program will produce unexpected results if exceptions occur, as explained in Figure 20.

Operating System Features for Trapping Floating-Point Exceptions

A direct way to turn on exception trapping is to call the operating system routine fp_trap. It uses the system hardware to detect floating-point exceptions and generates SIGFPE signals when exceptions occur. Fortran definitions for the values needed to call it are in the files /usr/include/fp_fort_c.f and fp_fort_t.f.

There are other related operating system routines that you can locate by reading the description of fp_trap.

The advantages of this approach include:

The disadvantages of this approach include:

Installing an Exception Handler

When a program that uses the XL Fortran or AIX exception-detection facilities encounters an exception condition, it generates a signal. This causes a branch to whatever handler is specified by the program. The information in this section, except the explanation of the -qsigtrap option, applies both to SIGTRAP and SIGFPE signals.

By default, the program stops after producing a core file, which you can use with a debugger to locate the problem. If you want to install a SIGTRAP signal handler, use the -qsigtrap option. It allows you to specify an XL Fortran handler that produces a traceback, or a handler you have written:

xlf95 -qflttrap=ov:und:en pi.f                             # Dump core on an exception
xlf95 -qflttrap=ov:und:en -qsigtrap pi.f                   # Uses the xl__trce handler
xlf95 -qflttrap=ov:und:en -qsigtrap=return_22_over_7 pi.f  # Uses any other handler

You can also install an alternative exception handler, either one supplied by XL Fortran or one you have written yourself, by calling the SIGNAL subroutine (defined in /usr/include/fexcp.h):

  INCLUDE 'fexcp.h'
  CALL SIGNAL(SIGTRAP,handler_name)
  CALL SIGNAL(SIGFPE,handler_name)

The XL Fortran exception handlers and related routines are:

xl_ _ieee
Produces a traceback and an explanation of the signal, and continues execution by supplying the default IEEE result for the failed computation. This handler allows the program to produce the same results as if exception detection was not turned on.

xl_ _trce
Produces a traceback and stops the program.

xl_ _trcedump
Produces a traceback and a core file and stops the program.

xl_ _sigdump
Provides a traceback that starts from the point at which it is called, and provides information about the signal. You can only call it from inside a user-written signal handler, and it requires the same parameters as other AIX signal handlers. It does not stop the program. To successfully continue, the signal handler must perform some cleanup after calling this subprogram.

xl_ _trbk
Provides a traceback that starts from the point at which it is called. You call it as a subroutine from your code, rather than specifying it with the -qsigtrap option. It requires no parameters. It does not stop the program.

All of these handler names contain double underscores to avoid duplicating names that you declared in your program. All of these routines work for both SIGTRAP and SIGFPE signals.

You can use the -g compiler option to get line numbers in the traceback listings. The file /usr/include/fsignal.h defines a Fortran derived type similar to the sigcontext structure in /usr/include/sys/signal.h. You can write a Fortran signal handler that accesses this derived type.
Related Information:Sample Programs for Exception Handling lists some sample programs that illustrate how to use these signal handlers or write your own. For more information on SIGNAL, see the "Intrinsic Procedures" chapter in the XL Fortran for AIX Language Reference.

Producing a Core File

To produce a core file, do not install an exception handler, or else specify the xl_ _trcedump handler.

Controlling the Floating-Point Status and Control Register

Before the -qflttrap suboptions or the -qsigtrap options, most of the processing for floating-point exceptions required you to change your source files to turn on exception trapping or install a signal handler. Although you can still do so, for any new applications we recommend that you use the options instead.

To control exception handling at run time, compile without the enable suboption of the -qflttrap option:

   xlf95 -qflttrap compute_pi.f     # Check all exceptions, but do not trap
   xlf95 -qflttrap=ov compute_pi.f  # Check one type, but do not trap

Then, inside your program, manipulate the fpstats array (defined in the include file /usr/include/fpdc.h) and call the fpsets subroutine to specify what exceptions should generate traps.

See the sample program that uses fpsets and fpgets in Selecting the Rounding Mode.

fpgets and fpsets Subroutines

The fpsets and fpgets subroutines provide a way to manipulate or query the floating-point status and control register. Instead of calling the operating system routines directly, you pass information back and forth in fpstat, an array of logicals. The following table shows the most commonly used array elements that deal with exceptions:

Figure 22. Exception Bits to Use with fpsets and fpgets
Array Element to
Set to Enable

Array Element to 
Check if Exception 
Occurred

Exception Indicated When .TRUE.

n/a fpstat(fpfx) Floating-point exception summary
n/a fpstat(fpfex) Floating-point enabled exception summary
fpstat(fpve) fpstat(fpvx) Floating-point invalid operation exception summary
fpstat(fpoe) fpstat(fpox) Floating-point overflow exception
fpstat(fpue) fpstat(fpux) Floating-point underflow exception
fpstat(fpze) fpstat(fpzx) Zero-divide exception
fpstat(fpxe) fpstat(fpxx) Inexact exception
fpstat(fpve) fpstat(fpvxsnan) Floating-point invalid operation exception (NaNS)
fpstat(fpve) fpstat(fpvxisi) Floating-point invalid operation exception (INF-INF)
fpstat(fpve) fpstat(fpvxidi) Floating-point invalid operation exception (INF/INF)
fpstat(fpve) fpstat(fpvxzdz) Floating-point invalid operation exception (0/0)
fpstat(fpve) fpstat(fpvximz) Floating-point invalid operation exception (INF*0)
fpstat(fpve) fpstat(fpvxvc) Floating-point invalid operation exception (invalid compare)
n/a fpstat(fpvxsoft) Floating-point invalid operation exception (software request), PowerPC only
n/a fpstat(fpvxsqrt) Floating-point invalid operation exception (invalid square root), PowerPC only
n/a fpstat(fpvxcvi) Floating-point invalid operation exception (invalid integer convert), PowerPC only

To explicitly check for specific exceptions at particular points in a program, use fpgets and then test whether the elements in fpstat have changed. Once an exception has occurred, the corresponding exception bit (second column in the preceding table) is set until it is explicitly reset, except for fpstat(fpfx), fpstat(fpvx), and fpstat(fpfex), which are reset only when the specific exception bits are reset.

An advantage of using the fpgets and fpsets subroutines (as opposed to controlling everything with suboptions of the -qflttrap option) includes control over granularity of exception checking. For example, you might only want to test if an exception occurred anywhere in the program when the program ends.

The disadvantages of this approach include the following:

For example, to trap floating-point overflow exceptions, but only in a certain section of the program, you would set fpstat(fpoe) to .TRUE. and call fpsets. After the exception occurs, the corresponding exception bit, fpstat(fpox), is .TRUE. until the program runs:

      call fpgets(fpstat)
      fpstat(fpox) = .FALSE.
      call fpsets(fpstat)   ! resetting fpstat(fpox) to .FALSE.

Sample Programs for Exception Handling

/usr/lpp/xlf/samples/floating_point contains a number of sample programs to illustrate different aspects of exception handling:

flttrap_handler.c  and  flttrap_test.f
A sample exception handler that is written in C, and a Fortran program that uses it.

xl_ _ieee.F  and  xl_ _ieee.c
Exception handlers that are written in Fortran and C that show how to substitute particular values for operations that produce exceptions. Even when you use support code such as this, the implementation of XL Fortran exception handling does not fully support the exception-handling environment that is suggested by the IEEE floating-point standard.

check_fpscr.f  and  postmortem.f
Show how to work with the fpsets and fpgets procedures and the fpstats array.

fhandler.F
Shows a sample Fortran signal handler and demonstrates the xl_ _sigdump procedure.

xl_ _trbk_test.f
Shows how to use the xl_ _trbk procedure to generate a traceback listing without stopping the program.

The sample programs are strictly for illustrative purposes only.

Causing Exceptions for Particular Variables

To mark a variable as "do not use", you can encode a special value called a signaling NaN (NaNS) in it. This causes an invalid exception condition any time that variable is used in a calculation.

If you use this technique, use the nans suboption of the -qfloat option, so that the program properly detects all cases where a NaNS is used, and one of the methods already described to generate corresponding SIGFPE or SIGTRAP signals.

Notes:

  1. Because a NaNS is never generated as the result of a calculation, and must be explicitly introduced to your program as a constant or in input data, you should not need to use this technique unless you deliberately use NaNS values in it.
  2. In previous XL Fortran releases, the -qfloat suboption was called spnans. In the future, use nans instead (although spnans still works, for backward compatibility).

Minimizing the Performance Impact of Floating-Point Exception Trapping

If you need to deal with floating-point exception conditions, but are concerned that doing so will make your program too slow, here are some techniques that can help minimize the performance impact:


[ Top of Page | Previous Page | Next Page | Table of Contents | Index ] © Copyright IBM Corporation 1990, 1998.