Previous | Contents | Index |
This chapter applies only to Compaq Fortran Tru64 UNIX systems. |
This chapter contains the following topics:
This chapter contains information about controlling exceptions that can occur during the run-time processing of floating-point numbers. These exceptions are underflow, division by zero, overflow, and invalid operation (such as the square root of a negative number).
See Section 9.4, Native IEEE Floating-Point Representations and Exceptional Values for information about the internal representation of floating-point numbers including exceptional values (such as plus infinity).
You can use these command-line options to direct the processing of Compaq Fortran floating-point numbers at run time:
The -fpen option, as explained in Section 3.44, lets you control floating-point exceptions according to the value of n . Table 3-3 contains the values of n and the corresponding results at run time when floating-point exceptions occur. These exceptions are underflow, division by zero, overflow, and invalid operation (such as the square root of a negative number).
Normally the -fpen option, along with the -check underflow and -synchronous_exceptions options, gives you adequate control over floating-point exception handling and reporting.
However, if any combination of these three options does not give you adequate control, then you can use the following:
For example, suppose you want to read a denormalized number from an unformatted file and perform calculations on it without generating an exception about an invalid operation. Suppose you also want to have divide-by-zero exceptions trapped and reported. While the -fpe3 option meets the first requirement, it also results in no trapping and reporting of divide-by-zero exceptions.
The general steps of the solution to this example are:
This example reappears later, in program fpe_div0_msg.f90 in Section 14.3.2.
Normally the -fpen , -check underflow , -synchronous_exceptions , and -fprm keyword options give you sufficient control over the processing of floating-point exceptions. Using file /usr/include/for_fpe_flags.f and function for_set_fpe can yield unanticipated results. |
Table 14-1 explains the bit definitions in file /usr/include/for_fpe_flags.f . The compiler automatically generates a call to for_set_fpe() , which is expected when the program begins execution. The argument to for_set_fpe() has the appropriate bits set (as defined in for_fpe_flags.f ) to achieve the documented behavior for the -fpen option specified at compile time. You have the option of changing this bit setting according to the individual bit definitions and their corresponding effects in Table 14-1. The function for_set_fpe works with the bit definitions to make the change.
For the default -fpe0 option, the compiler does not generate the call to for_set_fpe() . The run-time library automatically initializes floating-point exception behavior in this case at run-time initialization. |
Bit Name | Effect When Set |
---|---|
FPE_M_TRAP_UND | Requests delivery of underflow traps to the current signal handler. |
FPE_M_TRAP_OVF | Requests delivery of overflow traps to the current signal handler. |
FPE_M_TRAP_DIV0 | Requests delivery of division-by-zero traps to the current signal handler. |
FPE_M_TRAP_INV | Requests delivery of invalid operation traps to the current signal handler. |
FPE_M_MSG_UND | If the current signal handler is the default handler provided with the Fortran run-time library and bit FPE_M_TRAP_UND is also set, then the default handler sends a message to stderr for each of the first two occurrences of underflow traps. The default handler also sends a total count of underflow traps to stderr when the program terminates. If the current signal handler is not the default handler, then bit FPE_M_MSG_UND has no effect. |
FPE_M_MSG_OVF | If the current signal handler is the default handler provided with the Fortran run-time library and bit FPE_M_TRAP_OVF is also set, then the default handler sends a message to stderr for each of the first two occurrences of overflow traps. The default handler also sends a total count of overflow traps to stderr when the program terminates. If the current signal handler is not the default handler, then bit FPE_M_MSG_OVF has no effect. |
FPE_M_MSG_DIV0 | If the current signal handler is the default handler provided with the Fortran run-time library and bit FPE_M_TRAP_DIV0 is also set, then the default handler sends a message to stderr for each of the first two occurrences of divide-by-zero traps. The default handler also sends a total count of divide-by-zero traps to stderr when the program terminates. If the current signal handler is not the default handler, then bit FPE_M_MSG_DIV0 has no effect. |
FPE_M_MSG_INV | If the current signal handler is the default handler provided with the Fortran run-time library and bit FPE_M_TRAP_INV is also set, then the default handler sends a message to stderr for each of the first two occurrences of invalid operation traps. The default handler also sends a total count of invalid operation traps to stderr when the program terminates. If the current signal handler is not the default handler, then bit FPE_M_MSG_INV has no effect. |
FPE_M_ABRUPT_UND | Replaces denormalized numbers obtained as results of calculations with zeroes. |
FPE_M_ABRUPT_OVF | Reserved. |
FPE_M_ABRUPT_DIV0 | Reserved. |
FPE_M_ABRUPT_INV | Reserved. |
FPE_M_ABRUPT_DMZ | Replaces denormalized numbers used as input operands to floating-point instructions with zeroes. This does not have anything to do with reading data from unformatted files. |
Table 14-1 contains a list of bit definitions (in an INTEGER*4
variable) and their run-time effects when floating-point exceptions
occur. Functions
for_get_fpe
and
for_set_fpe
read and set the bits, respectively, after a program begins execution.
(The
-fpen
option also sets these bits when a program begins execution.)
14.3.1 Calling for_get_fpe
Function for_get_fpe has no argument. It returns an INTEGER*4 variable whose bits specify how the run-time library currently handles floating-point exceptions. The bits of the variable are defined in Table 14-1. for_get_fpe must be declared INTEGER(4).
For example, consider the following program. When compiled with the default -fpe0 option, this program displays the default settings of the bits in the INTEGER*4 variable:
PROGRAM TESTFGPE_FPE0 ! ! This program returns floating-point exception flags ! using function for_get_fpe(). ! integer*4 fpe_flags integer*4 for_get_fpe external for_get_fpe ! PRINT *, '' PRINT *, 'Start of program' fpe_flags = for_get_fpe() PRINT *, '' PRINT *, 'for_get_fpe() has returned, with option fpe0:' WRITE (*, 200) fpe_flags 200 FORMAT (' ', 'In B32 format: ', B32) PRINT *, '' PRINT *, 'End of program' END PROGRAM TESTFGPE_FPE0 |
The compilation and execution commands are:
% f90 -fpe0 testfgpe_fpe0.f90 % a.out |
The output from this program, with spaces added to the 32-character representation of variable fpe_flags, is:
Start of program for_get_fpe() has returned, with option fpe0: In B32 format: 1 0000 0000 0000 1110 End of program |
Compiling this program with a different value of the -fpen option gives different output. For example, if you compile with -fpe3 , variable fpe_flags contains zero.
For More Information:
Function for_set_fpe has a single argument: a floating-point exception behavior mask. This is an INTEGER*4 variable whose bits specify how the run-time library will handle floating-point exceptions. Function for_set_fpe must be declared INTEGER(4).
The bits of the mask variable are defined in Table 14-1. When the function executes, it both returns the previous value of the mask and changes the mask to the value of the argument. Recall that the -fpen option determines the value of the mask when the program begins to execute. Function for_set_fpe allows you to change the mask, and the handling of floating-point exceptions, after the program begins to execute.
Recall in Section 14.2 the example where the requirements are to read a denormalized number from an unformatted file and perform calculations on it without generating an invalid operation exception. Also, divide-by-zero exceptions must be trapped and reported. The -fpe3 option meets the first requirement. File /usr/include/for_fpe_flags.f and function for_set_fpe work together to meet the second requirement.
Consider program fpe_div0_msg.f90 :
program fpe_div0_msg ! Trap when division by zero occurs and display a message. ! Compile with the command f90 -fpe3 fpe_div0_msg.f90 external for_set_fpe ! External function integer*4 for_set_fpe ! Include the file with the definitions of the ! floating-point exceptions. include '/usr/include/for_fpe_flags.f' real*4 a,b,c integer*4 old_fpe_flags, new_fpe_flags ! Set the bits, of the argument to for_set_fpe(), to trap ! when division by zero occurs and to display a message. new_fpe_flags = FPE_M_TRAP_DIV0 + FPE_M_MSG_DIV0 old_fpe_flags = for_set_fpe(new_fpe_flags) a = 5.0 print *, '' print *, 'Give me 0.0' read *, b print *, 'Division by zero is next' c = a / b print *, 'The result of division by zero is', c print *, '' end |
In this program, at run time, division by zero occurs. This floating-point exception results in:
The compilation and execution commands are:
% f90 -fpe3 fpe_div0_msg.f90 % a.out |
The output from this program and user input (0.0) are:
Give me 0.0 0.0 Division by zero is next forrtl: error (73): floating divide by zero The result of division by zero is Infinity forrtl: info (299): 1 floating divide-by-zero traps |
Setting bit fpe_m_trap_div0 causes a trap when division by zero occurs and delivery of a signal to the current signal handler. Setting bit fpe_m_msg_div0 causes the Compaq Fortran run-time routines (the current and default signal handler) to display a message about the trapped division-by-zero floating-point exception. Because of compilation with -fpe3 , function for_set_fpe returns zero to variable old_fpe_flags.
For More Information:
The parameter file /usr/include/fordef.f contains symbols and INTEGER*4 values corresponding to the classes of floating-point representations. Some of these classes are exceptional ones such as bit patterns that represent positive denormalized numbers. See Section 9.4.8, Exceptional Floating-Point Representations.
With this file of symbols and with the FP_CLASS intrinsic function, you have the flexibility of identifying exceptional numbers so that, for example, you can replace positive and negative denormalized numbers with true zero.
The following is a simple example of identifying floating-point bit representations:
include '/usr/include/fordef.f' real*4 a integer*4 class_of_bits a = 57.0 ! Bit pattern is an Alpha finite number class_of_bits = fp_class(a) if ( class_of_bits .eq. for_k_fp_pos_norm .or. & class_of_bits .eq. for_k_fp_neg_norm ) then print *, a, ' is a non-zero and non-exceptional value' else print *, a, ' is zero or an exceptional value' end if end |
In this example, the symbol for_k_fp_pos_norm in file /usr/include/fordef.f plus the REAL*4 value 57.0 to the FP_CLASS intrinsic function results in the execution of the first print statement.
Table 14-2 explains the symbols in file /usr/include/fordef.f and their corresponding floating-point representations. Section 9.4.8, Exceptional Floating-Point Representations explains each representation.
Symbol Name | Class of Floating-Point Bit Representation |
---|---|
FOR_K_FP_SNAN | Signaling NaN |
FOR_K_FP_QNAN | Quiet NaN |
FOR_K_FP_POS_INF | Positive infinity |
FOR_K_FP_NEG_INF | Negative infinity |
FOR_K_FP_POS_NORM | Positive normalized finite number |
FOR_K_FP_NEG_NORM | Negative normalized finite number |
FOR_K_FP_POS_DENORM | Positive denormalized number |
FOR_K_FP_NEG_DENORM | Negative denormalized number |
FOR_K_FP_POS_ZERO | Positive zero |
FOR_K_FP_NEG_ZERO | Negative zero |
Another example of using file fordef.f and intrinsic function FP_CLASS follows. The goals of this program are to quickly read any 32-bit pattern into a REAL*4 number from an unformatted file with no exception reporting and to replace denormalized numbers with true zero:
include '/usr/include/fordef.f' real*4 a(100) integer*4 class_of_bits ! open an unformatted file as unit 1 ! ... read (1) a do i = 1, 100 class_of_bits = fp_class(a(i)) if ( class_of_bits .eq. for_k_fp_pos_denorm .or. & class_of_bits .eq. for_k_fp_neg_denorm ) then a(i) = 0.0 end if end do close (1) end |
You can compile this program with any value of -fpen . Intrinsic function FP_CLASS helps to find and replace denormalized numbers with zeroes before the program can attempt to perform calculations on the denormalized numbers. On the other hand, if this program did not replace denormalized numbers read from unit 1 with zeroes and the program was compiled with -fpe0 , then the first attempted calculation on a denormalized number would result in a floating-point exception.
File fordef.f and intrinsic function FP_CLASS can work together to identify NaNs. A variation of the previous example would contain the symbols for_k_fp_snan and for_k_fp_qnan in the IF statement. A faster way to do this is based on the intrinsic ISNAN function. One modification of the previous example, using ISNAN, follows:
! The ISNAN function does not need file /usr/include/fordef.f real*4 a(100) ! open an unformatted file as unit 1 ! ... read (1) a do i = 1, 100 if ( isnan (a(i)) ) then print *, 'Element ', i, ' contains a NaN' end if end do close (1) end |
You can compile this program with any value of -fpen .
Previous | Next | Contents | Index |