Handling Floating-Point Exceptions

If a floating-point exception is disabled (set to 1), it will not generate an interrupt signal if it occurs. The floating-point process will return an appropriate special value (for example, NaN or signed infinity), and the program will continue. If a floating-point exception is enabled (set to 0), it will generate an interrupt signal (software interrupt) if it occurs. The following table lists the floating-point exception signals:

Parameter Name Value in Hex Description
FPE$INVALID #81 Invalid result
FPE$DENORMAL #82 Denormal operand
FPE$ZERODIVIDE #83 Divide by zero
FPE$OVERFLOW #84 Overflow
FPE$UNDERFLOW #85 Underflow
FPE$INEXACT #86 Inexact precision

If a floating-point exception interrupt occurs and you do not have an exception handling routine, the run-time system will respond to the interrupt according to the behavior selected by the compiler options /fpe and /math_library. Remember, interrupts only occur if an exception is enabled (set to 0).

If you do not want the default system exception handling, you need to write your own interrupt handling routine:

Note that your interrupt handling routine must use the ATTRIBUTES C directive.

The drawback of writing your own routine is that your exception-handling routine cannot return to the process that caused the exception. This is because when your exception-handling routine is called, the floating-point processor is in an error condition, and if your routine returns, the processor is in the same state, which will cause a system termination. Your exception-handling routine can therefore either branch to another separate program unit or exit (after saving your program state and printing an appropriate message). You cannot return to a different statement in the program unit that caused the exception-handling routine, because a global GOTO does not exist, and you cannot reset the status word in the floating-point processor.

If you need to know when exceptions occur and also must continue if they do, you must disable exceptions so they do not cause an interrupt, then poll the floating-point status word at intervals with GETSTATUSFPQQ (ia32 only) to see if any exceptions occurred. To clear the status word flags, call the CLEARSTATUSFPQQ (ia32 only) routine.

Obviously, polling the floating-point status word at intervals creates processing overhead for your program. In general, you will want to allow the program to terminate if there is an exception. An example of an exception-handling routine follows. The exception-handling routine hand_fpe and the program that invokes it are both contained in SIGTEST.F90 in the Visual Fortran Samples folder ...\DF98\SAMPLES\TUTORIAL. The comments at the beginning of the SIGTEST.F90 file describe how to compile this example.

 ! SIGTEST.F90
 !Establish the name of the exception handler as the
 ! function to be invoked if an exception happens.
 ! The exception handler hand_fpe is attached below.
   USE DFLIB
      INTERFACE
        FUNCTION hand_fpe (sigid, except)
           !DEC$ ATTRIBUTES C :: hand_fpe
           INTEGER(4) hand_fpe
           INTEGER(2) sigid, except
        END FUNCTION
      END INTERFACE

 INTEGER(4) iret
 REAL(4) r1, r2
 r1 = 0.0
 iret = SIGNALQQ(SIG$FPE, hand_fpe)
 WRITE(*,*) 'Set exception handler. Return = ', iret
 ! Cause divide by zero exception
 r1 = 0.0
 r2 = 3/r1
 END

 ! Exception handler routine hand_fpe
   FUNCTION hand_fpe (signum, excnum)
     !DEC$ ATTRIBUTES C :: hand_fpe
     USE DFLIB
     INTEGER(2) signum, excnum
     WRITE(*,*) 'In signal handler for SIG$FPE'
     WRITE(*,*) 'signum = ', signum
     WRITE(*,*) 'exception = ', excnum
     SELECT CASE(excnum)
       CASE( FPE$INVALID )
         STOP ' Floating point exception: Invalid number'
       CASE( FPE$DENORMAL )
         STOP ' Floating point exception: Denormalized number'
       CASE( FPE$ZERODIVIDE )
         STOP ' Floating point exception: Zero divide'
       CASE( FPE$OVERFLOW )
         STOP ' Floating point exception: Overflow'
       CASE( FPE$UNDERFLOW )
         STOP ' Floating point exception: Underflow'
       CASE( FPE$INEXACT )
         STOP ' Floating point exception: Inexact precision'
       CASE DEFAULT
         STOP ' Floating point exception: Non-IEEE type'
     END SELECT
     hand_fpe = 1
   END