Jump to content United States-English
HP.com Home Products and Services Support and Drivers Solutions How to Buy
» Contact HP
More options
HP.com home
HP-UX Floating-Point Guide: HP 9000 Computers > Chapter 6 Floating-Point Trap Handling

Handling Traps

» 

Technical documentation

Complete book in PDF
» Feedback
Content starts here

 » Table of Contents

 » Glossary

 » Index

Once you have enabled traps, either by a compiler option or by a call to a routine, you need a mechanism for handling them when they occur. It may be convenient simply to have your program abort (particularly if you enable traps with a method that does not cause a core dump). You may, however, prefer to establish an error-handling routine that generates a helpful error message and exits the program gracefully.

HP 9000 systems provide the following methods of handling traps:

  • The ON statement (Fortran only)

  • The sigaction(2) function (C only)

We discuss these briefly in the following subsections.

You may want to continue execution after handling a trap, but you should be very cautious about doing so. The most important reason, of course, is that if your program encounters an exception, the result of at least that portion of your calculations is likely to be useless.

Another reason occurs if you use the C sigaction(2) function for error handling. Floating-point exceptions are hardware exceptions, whereas an error-handling process (such as the C sigaction(2) function or the HP Fortran ON statement) occurs in software. A hardware exception usually causes an operation to be interrupted at a point when values are stored in registers but not yet stored in memory. If you use sigaction(2) to try to substitute a new value for the one that caused the error, chances are you will return to a point later in the instruction sequence than the point at which the error occurred, so some essential steps may be eliminated and the register values may be invalid. This particular problem does not occur with the HP Fortran ON statement; the software updates the registers appropriately.

Using the ON Statement (Fortran only)

The ON statement may be used to handle arithmetic exceptions in both HP Fortran 90 and HP FORTRAN/9000. In HP FORTRAN/9000 the statement must be used in conjunction with the +T compiler option. In HP Fortran 90 it may be used in conjunction with the +fp_exception option, but this is not required.

The ON statement allows you to specify a particular action to be taken when a particular exception arises. The action may be any of the following:

  • ABORT (the default action). Specifying ABORT allows you to get the address where the error occurred, which may be useful in debugging.

  • IGNORE (usually not a good idea).

  • CALL sub (call a subroutine). If you call a subroutine to handle an IEEE exception, you must pass it one argument, which is of the same type as the type associated with the exception. If the subroutine returns, the program uses the assigned value of the argument as the result value of the operation that caused the handler to be invoked.

NOTE: A subroutine that handles an IEEE exception takes a different number of arguments from a subroutine that handles a math library error (as described in “Math Library Error Handling for Fortran”). See the HP FORTRAN/9000 Programmer's Guide for details. HP discourages the use of the ON statement to handle library errors in HP Fortran 90, but using it to handle arithmetic errors poses no problems.

For example, the following program calls the subroutine HANDLE_OFL to handle a DOUBLE PRECISION overflow. The subroutine prints a message describing the error, prints the biased value passed to the subroutine, then the correct value, and exits.

Example 6-3 Sample Program: overflow_on.f

      PROGRAM OVERFLOW_ON
DOUBLE PRECISION X, Y, Z

ON DOUBLE PRECISION OVERFLOW CALL HANDLE_OFL

X = 1.79D308
Y = 2.2D-308
Z = X / Y
WRITE(*,*) X, ' divided by', Y, ' = ', Z
END

SUBROUTINE HANDLE_OFL(A)
DOUBLE PRECISION A, T
INTEGER I
WRITE(*,*) 'overflow occurred'
WRITE(*,*) 'argument to HANDLE_OFL is ', A
C The result is 2**1536 too small
T = LOG10(A) + 1536 * LOG10(2D0)
I = T ! Get exponent
T = T - I
WRITE(*,*) 'the correct answer is', 10**T,
x ' times 10 to the power', I
STOP
END

See the PA-RISC 1.1 Architecture and Instruction Set Reference Manual for a full explanation of the bias of 1536; when traps are enabled, the IEEE standard requires that a biased result be returned.

If you compile and run this program using HP Fortran 90 and HP FORTRAN/9000 respectively, it produces the following result:

$ f90 overflow_on.f
overflow_on.f
program OVERFLOW_ON
external subroutine HANDLE_OFL

26 Lines Compiled
$ ./a.out
overflow occurred
argument to HANDLE_OFL is 3.375646885228544E+153
the correct answer is 8.13636363636275 times 10 to the power 615
$ f77 +T overflow_on.f 
overflow_on.f:
MAIN overflow_on:
handle_ofl:
$ ./a.out
overflow occurred
argument to HANDLE_OFL is 3.375646885228544+153
the correct answer is 8.13636363636275 times 10 to the power 615

One situation where it is useful to assign a value to the trap handler argument and continue program execution is that of an underflow exception (described in “Underflow Conditions”). Substituting a value of 0 for the result of an operation that underflows may be exactly what you want to do. In fact, the system may perform this substitution for you; the IEEE standard specifies that 0 may be the result of an operation that underflows, and on HP 9000 systems it often is (when the result of the operation is less than the smallest denormalized value). If you want to guarantee a result of 0, you can call a handler as follows:

Example 6-4 Sample Program: underflow_on.f

      PROGRAM UNDERFLOW_ON
DOUBLE PRECISION X, Y, Z

ON DOUBLE PRECISION UNDERFLOW CALL HANDLE_UFL

X = 1.0D0
Y = 1.79D308
Z = X / Y
PRINT 30, X, Y, Z
30 FORMAT (1PE11.4, ' divided by', 1PE11.4, ' = ', 1PE11.4)
END

SUBROUTINE HANDLE_UFL(A)
DOUBLE PRECISION A

WRITE(*,*) 'underflow occurred'
A = 0.0
RETURN
END

If you compile and run this program, it produces the following result:

$ f90 underflow_on.f
underflow_on.f
program UNDERFLOW_ON
external subroutine HANDLE_UFL

21 Lines Compiled
$ ./a.out
underflow occurred
1.0000E+00 divided by 1.7900+308 = 0.0000E+00
$ f77 +T underflow_on.f 
underflow_on.f:
MAIN underflow_on:
handle_ufl:
$ ./a.out
underflow occurred
1.0000E+00 divided by 1.7900+308 = .0000E+00

If your system supports fast underflow mode, you can use it both to guarantee a result of 0 for all underflows and to avoid the overhead of incurring a trap. You can enable fast underflow mode with either the +FP option (see “Command-Line Mode Control: The +FP Compiler Option”) or the fesetflushtozero routine (see “Underflow Mode: fegetflushtozero and fesetflushtozero”).

The ON statement is documented fully in the HP Fortran 90 Programmer's Reference and the HP FORTRAN/9000 Programmer's Guide.

Using the sigaction(2) Function (C only)

For C programs, the standard method of handling errors is to use the ­sigaction(2) function. The function establishes the address of a signal-handling function that is called whenever the specified HP-UX signal is raised. The major problem with this method is that there is only one HP-UX signal, SIGFPE, for all IEEE and integer exceptions. When SIGFPE is raised, the only way to find out which exception generated the signal is to examine the floating-point exception registers, which can be obtained from the sigcontext structure that is an argument to the sigaction(2) function. (Or you can enable a trap for only one exception.)

The following C program uses fesettrapenable to enable a trap for the overflow exception, and calls sigaction(2) to specify that the function handle_sigfpe is to be called when SIGFPE is raised.

Example 6-5 Sample Program: overflow_sig.c

/*************************************************************/
#include <stdio.h>
#include <math.h>
#include <fenv.h>
#include <signal.h>

int traps;
fexcept_t flags;

/* signal handler for floating-point exceptions */
void handle_sigfpe(int signo, siginfo_t *siginfo,
ucontext_t *ucontextptr)
{
void print_flags(int);
void print_traps(int);

printf("Raised signal %d -- floating point error\n", signo);
printf("code is %d\n", siginfo->si_code);
printf("fr0L is %08x\n", ucontextptr->uc_mcontext.ss_frstat);
print_traps(traps);
fegetexceptflag(&flags, FE_ALL_EXCEPT);
print_flags(flags);
exit(-1);
}

int main(void)
{
void print_flags(int);
void print_traps(int);
double x, y, z;
struct sigaction act;

act.sa_handler = &handle_sigfpe;
act.sa_flags = SA_SIGINFO;

/* establish the signal handler */
sigaction(SIGFPE, &act, NULL);

fesettrapenable(FE_OVERFLOW);
traps = fegettrapenable();
print_traps(traps);

x = 1.79e308;
y = 2.2e-308;
z = x / y; /* divide very big by very small */
printf("%g / %g = %g\n", x, y, z);
} /* continued */
/*************************************************************/

Example 6-6 Sample Program: overflow_sig.c (Cont.)

/*************************************************************/
void print_flags(int flags)
{
if (flags & FE_INEXACT)
printf(" inexact result flag set\n");
if (flags & FE_UNDERFLOW)
printf(" underflow flag set\n");
if (flags & FE_OVERFLOW)
printf(" overflow flag set\n");
if (flags & FE_DIVBYZERO)
printf(" division by zero flag set\n");
if (flags & FE_INVALID)
printf(" invalid operation flag set\n");

if (!(flags & FE_ALL_EXCEPT))
printf(" no exception flags are set\n");
}

void print_traps(int traps)
{
if (traps & FE_INEXACT)
printf(" inexact result trap set\n");
if (traps & FE_UNDERFLOW)
printf(" underflow trap set\n");
if (traps & FE_OVERFLOW)
printf(" overflow trap set\n");
if (traps & FE_DIVBYZERO)
printf(" division by zero trap set\n");
if (traps & FE_INVALID)
printf(" invalid operation trap set\n");

if (!(traps & FE_ALL_EXCEPT))
printf(" no trap enables are set\n");
}
/*************************************************************/

If you compile and run this program, it produces a result like the following:

$ cc overflow_sig.c -lm 
$ ./a.out
overflow trap set
Raised signal 8 -- floating point error
code is 14
fr0L is 08081844
overflow trap set
inexact result flag set

The code 14 signifies an assist exception trap (see signal(5)), which indicates a floating-point exception.

The main advantage of using a signal handler is that it eliminates the core dump that you get without it if you compile with +FP or use fesettrapenable.

Printable version
Privacy statement Using this site means you accept its terms Feedback to webmaster
© 1997 Hewlett-Packard Development Company, L.P.