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.
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.fYou 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:
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.
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:
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:
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. |
To produce a core file, do not install an exception handler, or else specify the xl_ _trcedump handler.
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.
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.
/usr/lpp/xlf/samples/floating_point contains a number of sample programs to illustrate different aspects of exception handling:
The sample programs are strictly for illustrative purposes only.
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:
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:
xlf90 -qflttrap=underflow:enable:imprecise does_underflows.f
imprecise makes the program check for the specified exceptions only on entry and exit to subprograms that perform floating-point calculations. This means that XL Fortran will eventually detect any exception, but you will know only the general area where it occurred, not the exact location.
When you specify -qflttrap without imprecise, a check for exceptions follows each floating-point operation. If all your exceptions occur during calls to routines that are not compiled with -qflttrap (such as library routines), using imprecise is generally a good idea, because identifying the exact location will be difficult anyway.