The Fortran compiler supports several kinds of floating-point exceptions; a summary of their masked (or default) responses is given below:
overflow: Overflow is signaled whenever the destination format’s largest finite number is exceeded in magnitude by what would have been the rounded floating-point result. The result computed is rounding mode specific:
Round-to-nearest (default): +/- Infinity in specified precision
Round-to-zero: +/- Maximum Number in specified precision
Round-to-+Infinity: +Infinity or –(Maximum Positive Number) in specified precision
Round-to--Infinity: (Maximum Positive Number) or -Infinity in specified precision
For example, in round-to-nearest mode 1E30 * 1E30 overflows the single-precision floating-point range and results in a +Infinity; -1E30 * 1E30 results in a -Infinity.
divide-by-zero:
Divide-by-zero is signaled when the divisor is zero and the dividend is
a finite nonzero number. The computed result is a correctly signed Infinity.
For example, 2.0E0/+0.0 produces a divide-by-zero exception and results
in a +Infinity; -2.0E0/+0.0 produces a divide-by-zero exception and results
in a –Infinity.
underflow: Underflow occurs when a computed result (of an add, subtract, multiply, divide, or math function call) falls beyond the minimum range in magnitude of normalized numbers of the floating-point data type. Each floating-point type (32-, 64-, and 128-bit) has a denormalized range where very small numbers can be represented with some loss of precision. This is called gradual underflow. For example, the lower bound for normalized single-precision float-point is approximately 1E-38, while the lower bound for denormalized single-precision float-point is approximately 1E-45. Results falling below the lower bound of the denormalized range simply become zero. 1E-30 / 1E10 underflows the normalized range but not the denormalized range so the result is the denormal value 1E-40. 1E-30 / 1E30 underflows the entire range and the result is zero.
invalid: Invalid occurs when operands to the basic floating-point operations or math function inputs produce an undefined (QNaN) result. Some examples include:
SNaN operand in any floating-point operation or math function call.
Division of zeroes: (+/-0.0)/(+/-0.0)
Sum of Infinities having different signs: Infinity + (-Infinity)
Difference of Infinities having the same sign: (+/-Infinity) – (+/-Infinity)
Product of signed Infinities with zero: (+/-Inf) * 0
Math Function Domain Errors: log(negative), sqrt(negative), asin(|x}>1)
The -fpen option allows some control over the results of floating-point exceptions.
-fpe0 restricts floating-point exceptions as follows:
Enables the overflow,
the divide-by-zero, and the invalid floating-point exceptions. The program
will print an error message and abort if any of these exceptions occurs.
If a floating-point underflow
occurs, the result is set to zero and execution continues. This
is called flush-to-zero.
This options sets -IPF_fp_speculationstrict if no specific -IPF_fp_speculation option is specified.
-fpe1 restricts only floating-point underflow:
Floating-point overflow, floating-point divide-by-zero, and floating-point invalid produce exceptional values (NaN and signed Infinities) and execution continues.
If a floating-point underflow occurs, the result is set to zero and execution continues.
-fpe3, the default, allows full floating-point exception behavior:
Floating overflow, floating divide-by-zero, and floating invalid produce exceptional values (NaN and signed Infinities) and execution continues.
Floating underflow is gradual: denormalized values are produced until the result becomes 0.
The -fpe option affects the Fortran main program only. The floating-point exception behavior set by the Fortran main program remains in effect throughout the execution of the entire program unless changed by the programmer. If the main program is not Fortran, the user can use the Fortran intrinsic FOR_SET_FPE to set the floating-point exception behavior.
When compiling different routines in a program separately, you should use the same value of n in -fpen.
An example follows:
IMPLICIT NONE
real*4 res_uflow, res_oflow
real*4 res_dbyz, res_inv
real*4 small, big, zero, scale
small = 1.0e-30
big = 1.0e30
zero = 0.0
scale = 1.0e-10
! IEEE underflow condition (Underflow Raised)
res_uflow = small * scale
write(6,100)"Underflow: ",small, " *", scale, " = ", res_uflow
! IEEE overflow condition (Overflow Raised)
res_oflow = big * big
write(6,100)"Overflow: ", big, " *", big, " = ", res_oflow
! IEEE divide-by-zero condition (Divide by Zero Raised)
res_dbyz = -big / zero
write(6,100)"Div-by-zero: ", -big, " /", zero, " = ", res_dbyz
! IEEE invalid condition (Invalid Raised)
res_inv = zero / zero
write(6,100)"Invalid: ", zero, " /", zero, " = ", res_inv
100 format(A14,E8.1,A2,E8.1,A2,E10.1)
end
Consider the following command line:
ifort fpe.f -fpe0 -g
The following output is produced:
./a.out
Underflow: 0.1E-29 * 0.1E-09 = 0.0E+00
forrtl: error (72): floating overflow
Image PC Routine Line Source
a.out 0804A063 Unknown Unknown Unknown
a.out 08049E78 Unknown Unknown Unknown
Unknown B746B748 Unknown Unknown Unknown
a.out 08049D31 Unknown Unknown Unknown
Aborted
The following command line uses -fpe1:
ifort fpe.f -fpe1 -g
The following output is produced:
./a.out
Underflow: 0.1E-29 * 0.1E-09 = 0.0E+00
Overflow: 0.1E+31 * 0.1E+31 = Infinity
Div-by-zero: -0.1E+31 / 0.0E+00 = -Infinity
Invalid: 0.0E+00 / 0.0E+00 = NaN
The following command line uses -fpe3:
ifort fpe.f -fpe3 -g
The following output is produced:
./a.out
Underflow: 0.1E-29 * 0.1E-09 = 0.1E-39
Overflow: 0.1E+31 * 0.1E+31 = Infinity
Div-by-zero: -0.1E+31 / 0.0E+00 = -Infinity
Invalid: 0.0E+00 / 0.0E+00 = NaN
The -ftz option affects the results of floating underflow in the following ways:
-ftz results in abrupt underflow to 0: the result of a floating underflow is set to zero and execution continues. -ftz also makes a denomal value used in a computation be treated as a zero so no floating invalid exception will occur.
-ftz- results in gradual underflow to 0: the result of a floating underflow is a denormalized number or a zero.
If the optimization level is -O2 or -O3, abrupt underflow to zero is set by default. At lower optimization levels, gradual underflow to 0 is the default.
On IA-32 and Intel® EM64T systems, explicitly setting -ftz can degrade performance since the generated code stream must be synchronized after each floating-point instruction to allow for abrupt underflow fix-up. Abrupt underflow in SSE is handled by setting the FTZ bit in the MXCSR register; with SSE and SSE2 code, there is no performance degradation and possibly even a performance gain due to the fact that the hardware handles the denormals. The default setting of abrupt underflow affects the SSE hardware, not the instruction stream.
On Itanium®-based processors, gradual underflow to 0 can degrade performance. You can improve performance by using higher optimization levels to get the default abrupt underflow or explicitly setting -ftz.
See Also: