If a floating-point exception is disabled (its bit is set to 1 with SETCONTROLFPQQ (x87 arithmetic only), it will not generate an interrupt signal if it occurs. The floating-point process may return an appropriate special value (for example, NaN or signed infinity) or may return an acceptable value (for example, in the case of a denormal operand), and the program will continue. If a floating-point exception is enabled (its bit is 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 option /fpe. 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:
Write a function that performs whatever special behavior you require on the interrupt.
Register that function as the procedure to be called on that interrupt with SIGNALQQ.
Note that your interrupt handling routine must use the cDEC$ ATTRIBUTES option C.
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 (IA-32 architecture only) to see if any exceptions occurred. To clear the status word flags, call the CLEARSTATUSFPQQ (IA-32 architecture only) routine.
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 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 IFPORT
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 IFPORT
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