X3J3/96-090
Date: May 10, 1996
To: X3J3
From: John K. Reid
Subject: Draft TR for Floating-Point Exception Handling
0. NOTES
This is a draft Technical Report using procedures in two modules for
exception handling. I will explain the changes made since the version
of 2 February 1996.
I have made the following changes with the consent of X3J3 in February:
1. Changed IEEE_MODE to IEEE_LEVEL. This seems to me to be a
better name.
2. Made IEEE_TEST_FLAG into a subroutine. The case for a subroutine is
that it gives a clear separation between statements that can change the
flag values and those that can access them. It avoids breaking the rule
that a function value should depend solely on argument values, which
applies to all the intrinsic functions.
X3J3 made no further suggestions for changes at its February meeting.
This version has draft edits to the standard (section 3). Constructing
the edits made me want the following technical changes:
1. Change IEEE_HALT to IEEE_SET_HALTING_MODE, since this does not
cause a halt but a change to the halting mode.
2. Remove the optional argument X from IEEE_SUPPORT_HALTING,
IEEE_GET_HALTING_MODE, and IEEE_SET_HALTING_MODE. It seems to me that we
want the processor to halt or continue after an IEEE exception occurs,
regardless of the cause of the exception. Picky rules would otherwise
be needed for mixed kind operations.
3. Change IEEE_TEST_FLAG to IEEE_GET_FLAG, since this is more
appropriate for a subroutine and is consistent with
IEEE_GET_HALTING_MODE.
4. Remove the subroutine IEEE_CLEAR_FLAG and add the argument
FLAG_VALUE to IEEE_SET_FLAG. This is to allow the old values of several
flags to be restored by a single procedure call.
5. Make IEEE_GET_HALTING_MODE and IEEE_SET_HALTING_MODE elemental for
consistency with IEEE_GET_FLAG and IEEE_SET_FLAG, and to allow several
exceptions to be treated together.
6. IEEE_COPYSIGN => IEEE_COPY_SIGN (since copy and sign are words), and
IEEE_NEXTAFTER => IEEE_NEXT_AFTER (since next and after are words).
I asked the Development Body to consider these on 22 April and there
have been no objections.
7. At the request of DIN, I have made the edits highlighted with change
bars. Please consider carefully the paragraph on exception handling in
the existing intrinsics that I have added to the edits for 15.2. For
the enable proposal, many people had a model of two versions of the
intrinsics: one for within enable blocks and one for outside them. Do
we need something similar here? The new paragraph reflects my
(tentantive) view is that we should not require invalid intrinsic calls
to result in continued execution, but allow processors to do this.
I wonder about making the changes:
8. IEEE => STD either globally or partially. We might leave IEEE
for the elemental functions since they apply only to IEEE data types.
DIN would like it to be clearer that non-IEEE processors are being
addressed.
9. Add the function IEEE_RINT for rounding to an integer value of the
same real kind, using the current rounding mode (see section 5.4 of
IEEE standard). This is my interpretation of DIN's request. I see no
need for IEEE_INT, since INT(IEEE_RINT(X)) would do the job. Are there
any more functions needed to support IEEE?
I would appreciate hearing of any objections to changes 1-7 and opinions
on 8-9.
1. RATIONALE
Exception handling is required for the development of robust and
efficient numerical software. In particular, it is necessary in order
to be able to write portable scientific libraries. In numerical
Fortran programming, current practice is to employ whatever exception
handling mechanisms are provided by the system/vendor. This clearly
inhibits the production of fully portable numerical libraries and
programs. It is particularly frustrating now that IEEE arithmetic is so
widely used, since built into it are the five conditions: overflow,
invalid, divide_by_zero, underflow, and inexact. Our aim to to provide
support for these conditions.
We have taken the opportunity to provide support for other aspects of |
the IEEE standard through a set of elemental functions that are |
applicable only to IEEE data types. |
This proposal involves two standard modules, IEEE_ARITHMETIC and
IEEE_SUBSET, each containing four derived types, some named constants
of these types, an integer named constant IEEE_LEVEL, and a collection
of simple procedures. They allow the flags to be tested, cleared, set,
saved, or restored. To facilitate maximum performance, each of the
proposed functions does very little processing of arguments. In many
cases, a processor may generate only a few inline machine code
instructions rather than library calls. Any feature supported on a
processor for IEEE_SUBSET must also be supported for IEEE_ARITHMETIC.
Some processors may execute faster using IEEE_SUBSET.
In order to allow for the maximum number of processors to provide the
maximum value to users, we do NOT require complete IEEE conformance.
What a vendor must do is to provide the module, and support the
overflow and divide-by-zero flags and the basic inquiry functions. A
user must utilize the inquiry functions to determine if he or she can
count on specific features of the IEEE standard, before using other
inquiry or value setting procedures.
Note that a processor ought not implement these as "macros", as IEEE
conformance is often controlled by compiler switches. A processor which
offers a switch to turn off a facility should adjust the values
returned for these inquiries. For example, a processor which allows
gradual underflow to be turned off (replaced with flush to zero) should
return .FALSE. for IEEE_SUPPORT_DENORMAL(X) when a source file is
processed with that option on. Naturally it should return .TRUE. when
that option is not in effect.
The most important use of a floating-point exception handling facility
is to make possible the development of much more efficient software
than is otherwise possible. The following "hypotenuse" function,
sqrt(x**2 + y**2), illustrates the use of the facility in developing
efficient software.
REAL FUNCTION HYPOT(X, Y)
! In rare circumstances this may lead to the signaling of the OVERFLOW flag
USE, INTRINSIC :: IEEE_ARITHMETIC
REAL X, Y
REAL SCALED_X, SCALED_Y, SCALED_RESULT
LOGICAL, DIMENSION(2) :: FLAGS, OLD_FLAGS
TYPE (IEEE_FLAG_TYPE), PARAMETER, DIMENSION(2) :: &
OUT_OF_RANGE = (/ IEEE_OVERFLOW, IEEE_UNDERFLOW /)
INTRINSIC SQRT, ABS, EXPONENT, MAX, DIGITS, SCALE
! Store the old flags and clear them
CALL IEEE_GET_FLAG(OUT_OF_RANGE,OLD_FLAGS)
CALL IEEE_SET_FLAG(OUT_OF_RANGE,.FALSE.)
! Try a fast algorithm first
HYPOT = SQRT( X**2 + Y**2 )
CALL IEEE_GET_FLAG(OUT_OF_RANGE,FLAGS)
IF ( ANY(FLAGS) ) THEN
CALL IEEE_SET_FLAG(OUT_OF_RANGE,.FALSE.)
IF ( X==0.0 .OR. Y==0.0 ) THEN
HYPOT = ABS(X) + ABS(Y)
ELSE IF ( 2*ABS(EXPONENT(X)-EXPONENT(Y)) > DIGITS(X)+1 ) THEN
HYPOT = MAX( ABS(X), ABS(Y) )! one of X and Y can be ignored
ELSE ! scale so that ABS(X) is near 1
SCALED_X = SCALE( X, -EXPONENT(X) )
SCALED_Y = SCALE( Y, -EXPONENT(X) )
SCALED_RESULT = SQRT( SCALED_X**2 + SCALED_Y**2 )
HYPOT = SCALE( SCALED_RESULT, EXPONENT(X) ) ! may cause overflow
END IF
END IF
IF(OLD_FLAGS(1)) CALL IEEE_SET_FLAG(IEEE_OVERFLOW,.TRUE.)
IF(OLD_FLAGS(2)) CALL IEEE_SET_FLAG(IEEE_UNDERFLOW,.TRUE.)
END FUNCTION HYPOT
An attempt is made to evaluate this function directly in the fastest
possible way. (Note that with hardware support, exception checking is
very efficient; without language facilities, reliable code would
require programming checks that slow the computation significantly.)
The fast algorithm will work almost every time, but if an exception
occurs during this fast computation, a safe but slower way evaluates
the function. This slower evaluation may involve scaling and
unscaling, and in (very rare) extreme cases this unscaling can cause
overflow (after all, the true result might overflow if X and Y are both
near the overflow limit). If the overflow or underflow flag is signaling on
entry, it is reset on return, so that earlier exceptions are not
lost.
Can all this be accomplished without the help of an exception handling
facility? Yes, it can - in fact, the alternative code can do the job,
but of course it is much less efficient. That's the point. The HYPOT
function is special, in this respect, in that the normal and
alternative codes try to accomplish the same task. This is not always
the case. In fact, it very often happens that the alternative code
concentrates on handling the exceptional cases and is not able to
handle all of the non-exceptional cases. When this happens, a program
which cannot take advantage of hardware flags could have a structure
like the following:
if ( in the first exceptional region ) then
handle this case
else if ( in the second exceptional region ) then
handle this case
:
else
execute the normal code
end
But this is not only inefficient, it also "inverts" the logic of the
computation. For other examples, see Hull, Fairgrieve and Tang (1994)
and Demmel and Li (1994).
The code for the HYPOT function can be generalized in an obvious
way to compute the Euclidean Norm, sqrt( x(1)**2 + x(2)**2 + ... +
x(n)**2 ), of an n-vector; the generalization of the alternative code is
not so obvious (though straightforward) and will be much slower
relative to the normal code than is the case with the HYPOT function.
Of the five IEEE conditions, underflow and inexact are obviously milder
than the other three (inexact is particularly mild and signals almost
all the time in typical codes). We therefore group the other three
together as 'usual'.
There is a need for further intrinsic conditions in connection with
reliable computation. Examples are
a. INSUFFICIENT_STORAGE for when the processor is unable to find
sufficient storage to continue execution.
b. INTEGER_OVERFLOW and INTEGER_DIVIDE_BY_ZERO for when an
intrinsic integer operation has a very large result or
has a zero denominator.
c. INTRINSIC for when an intrinsic procedure has been unsuccessful.
d. SYSTEM_ERROR for when a system error occurs.
This proposal has been designed to allow such enhancements in the future.
References
Demmel, J.W. and Li, X. (1994). Faster Numerical Algorithms via
Exception Handling. IEEE Transactions on Computers, 43,
no. 8, 983-992.
Hull, T.E., Fairgrieve, T.F., and Tang, T.P.T. (1994).
Implementing complex elementary functions using exception handling.
ACM Trans. Math. Software 20, 215-244.
2. TECHNICAL SPECIFICATION
2.1 The model
This proposal is based on the IEEE model with flags for the
floating-point exceptions (invalid, overflow, divide-by-zero,
underflow, inexact), a flag for the rounding mode (nearest, up, down,
to zero), and flags for whether halting occurs following exceptions. It
is not necessary for the hardware to have any such flags (they may be
simulated by software) or for it to support all the modes. Inquiry
procedures are available for determining the extent of support. The
minimum requirement is for the support of overflow and divide-by-zero.
Inquiries are in terms of reals, but the same level of support is
provided for the corresponding complex kind.
As well as the IEEE exceptions, the model contains the
exceptions 'usual' and 'all'. The flag usual is regarded as signaling
if any of invalid, overflow, divide-by-zero is signaling. Explicitly
setting usual (by invoking a procedure) has the corresponding effect on
all three flags. The flag all is similarly related to all five flags.
Some hardware may execute faster with compiled code that provides only
partial support of these features than with code than provides fuller
support. This proposal therefore involves two intrinsic modules, which
gives the programmer control over the extent of support. They are named
IEEE_ARITHMETIC and IEEE_SUBSET. Any feature supported on a processor
for IEEE_SUBSET must also be supported for IEEE_ARITHMETIC.
The modules contain four derived types (section 2.3), an integer
constant to control the level of support (section 2.4), and a
collection of procedures (sections 2.5 to 2.10). None of the procedures
is permitted as an actual argument.
2.2 The use statement for an intrinsic module
New syntax on the USE statement provides control over whether it is
intended to access an intrinsic module:
USE, INTRINSIC :: IEEE_ARITHMETIC
or not:
USE, NON_INTRINSIC :: MY_IEEE_ARITHMETIC
The INTRINSIC statement is not extended. For the Fortran 90 form
USE IEEE_ARITHMETIC
the processor looks first for a non-intrinsic module.
2.3 The derived types
The modules contain the following derived types
1. IEEE_FLAG_TYPE, for identifying a particular exception flag. Its
only possible values are those of constants defined in the module:
IEEE_INVALID, IEEE_OVERFLOW, IEEE_DIVIDE_BY_ZERO, IEEE_USUAL,
IEEE_UNDERFLOW, IEEE_INEXACT, and IEEE_ALL.
2. IEEE_CLASS_TYPE, for identifying a class of floating-point values.
Its only possible values are those of constants defined in the
module: IEEE_SIGNALING_NAN, IEEE_QUIET_NAN, IEEE_NEGATIVE_INF,
IEEE_NEGATIVE_NORMAL, IEEE_NEGATIVE_DENORMAL, IEEE_NEGATIVE_ZERO,
IEEE_POSITIVE_ZERO, IEEE_POSITIVE_DENORMAL, IEEE_POSITIVE_NORMAL,
IEEE_POSITIVE_INF.
3. IEEE_ROUND_TYPE, for identifying a particular rounding mode. Its
only possible values are those of constants defined in the module:
IEEE_NEAREST, IEEE_TO_ZERO, IEEE_UP, IEEE_DOWN, and IEEE_OTHER.
4. IEEE_STATUS_TYPE, for saving the current floating point status.
2.4 The level of support
Both modules contain the constant IEEE_LEVEL of type default integer.
It has the value 1 in IEEE_SUBSET and the value 2 in IEEE_ARITHMETIC.
The extent of IEEE support must be no less for IEEE_ARITHMETIC than for
IEEE_SUBSET. If a scoping unit has access to IEEE_LEVEL of
IEEE_ARITHMETIC, the scoping unit must provide the corresponding level
of support. If a scoping unit has access to IEEE_LEVEL of IEEE_SUBSET
and does not have access to IEEE_LEVEL of IEEE_ARITHMETIC, the scoping
unit must provide the subset level of support. Execution may be faster
with the subset. If a scoping unit has access to neither IEEE_LEVEL,
the level of support is processor determined, and need not include
support for any exceptions. Following execution of code in such a
scoping unit, the values of the flags are processor determined.
The minimum requirement when IEEE_LEVEL of either module is accessible |
is for the support of IEEE_OVERFLOW and IEEE_DIVIDE_BY_ZERO. Whether |
the other exceptions are supported may be determined by the elemental |
inquiry function IEEE_SUPPORT_FLAG, see section 2.6. The extent of further|
support for the IEEE standard may be determined by the other inquiry |
functions of section 2.6. |
2.5 The exception flags
The flags are initially quiet and signal when an exception occurs. The
value of a flag is determined by the elemental subroutine
IEEE_GET_FLAG (FLAG,FLAG_VALUE)
where FLAG is of type IEEE_FLAG_TYPE and FLAG_VALUE is of type default
LOGICAL. Being elemental allows an array of flag values to be obtained
at once and obviates the need for a list of flags.
Flag values may be assigned by the elemental subroutine
IEEE_SET_FLAG (FLAG,FLAG_VALUE)
An exception must not signal if this could arise only during |
execution of a process further to those required or permitted by the |
standard. For example, the statement |
IF (F(X)>0.) Y = 1.0/Z |
must not signal IEEE_DIVIDE_BY_ZERO when both F(X) and Z are zero and the |
statement |
WHERE(A>0.0) A = 1.0/A |
must not signal IEEE_DIVIDE_BY_ZERO. On the other hand, when |
X has the value 1.0 and Y has the value 0.0, the expression |
X>0.00001 .OR. X/Y>0.00001 |
is permitted to cause the signaling of IEEE_DIVIDE_BY_ZERO. |
2.6 Inquiry functions for the features supported
The modules contain the following inquiry functions: |
IEEE_SUPPORT_DATATYPE([X]) True if the processor supports IEEE arithmetic
for all reals (X absent) or for reals of the same kind type parameter as
the argument X. Here support means employing an IEEE data format and
performing the operations of +, -, and * as in the IEEE standard
whenever the operands and result all have normal values.
IEEE_SUPPORT_DENORMAL([X]) True if the processor supports the IEEE
gradual underflow facility for all reals (X absent) or for reals of
the same kind type parameter as the argument X.
IEEE_SUPPORT_DIVIDE([X]) True if the processor supports IEEE divide
for all reals (X absent) or for reals of the same kind type parameter
as the argument X.
IEEE_SUPPORT_FLAG(FLAG [, X]) True if the processor supports an
exception flag for all reals (X absent) or for reals of the same kind
type parameter as the argument X.
IEEE_SUPPORT_HALTING(FLAG) True if the processor supports the
ability to control during program execution whether to abort or
continue execution after an exception.
IEEE_SUPPORT_INF([X]) True if the processor supports the IEEE infinity
facility for all reals (X absent) or for reals of the same kind type
parameter as the argument X.
IEEE_SUPPORT_NAN([X]) True if the processor supports the IEEE
Not-A-Number facility for all reals (X absent) or for reals of the
same kind type parameter as the argument X.
IEEE_SUPPORT_ROUNDING(ROUND_VALUE [, X]) True if the processor
supports a particular rounding mode for all reals (X
absent) or for reals of the same kind type parameter as the argument
X. Here, support includes the ability to change the mode by
CALL IEEE_SET_ROUNDING(ROUND_VALUE).
IEEE_SUPPORT_SQRT([X]) True if the processor supports IEEE square root
for all reals (X absent) or for reals of the same kind type parameter
as the argument X.
IEEE_SUPPORT_STANDARD([X]) True if the processor supports all the IEEE
facilities defined in this standard for all reals (X absent) or for
reals of the same kind type parameter as the argument X.
2.7. Elemental functions
The modules contain the following elemental functions for reals X and Y |
for which IEEE_SUPPORT_DATATYPE(X) and IEEE_SUPPORT_DATATYPE(Y) are |
true: |
IEEE_CLASS(X) Returns the IEEE class (see Section 2.3 for the possible
values).
IEEE_COPY_SIGN(X,Y) IEEE copysign function, that is X with the sign of Y.
IEEE_IS_FINITE(X) IEEE finite function. True if CLASS(X) has one of
the values IEEE_NEGATIVE_NORMAL, IEEE_NEGATIVE_DENORMAL,
IEEE_NEGATIVE_ZERO, IEEE_POSITIVE_ZERO, IEEE_POSITIVE_DENORMAL,
IEEE_POSITIVE_NORMAL.
IEEE_IS_NAN(X) True if the value is IEEE Not-a-Number.
IEEE_IS_NEGATIVE(X) True if the value is negative.
IEEE_IS_NORMAL(X) True if the value is a normal number.
IEEE_LOGB(X) IEEE logb function, that is, the unbiased exponent of X.
IEEE_NEXT_AFTER(X,Y) Returns the next representable neighbor of X in
the direction toward Y.
IEEE_SCALB (X,I) Returns X * 2**I.
IEEE_SQRT(X) Square root as defined in the IEEE standard.
IEEE_UNORDERED(X,Y) IEEE unordered function. True if X or Y is a NaN
and false otherwise.
IEEE_VALUE(X, CLASS) Generate an IEEE value. The
value of CLASS is permitted to be
(i) IEEE_SIGNALING_NAN or IEEE_QUIET_NAN if IEEE_SUPPORT_NAN(X) has
the value true,
(ii) IEEE_NEGATIVE_INF or IEEE_POSITIVE_INF if IEEE_SUPPORT_INF(X)
has the value true,
(iii) IEEE_NEGATIVE_DENORMAL or IEEE_POSITIVE_DENORMAL if
IEEE_SUPPORT_DENORMAL(X) has the value true,
(iv) IEEE_NEGATIVE_NORMAL, IEEE_NEGATIVE_ZERO, IEEE_POSITIVE_ZERO |
or IEEE_POSITIVE_NORMAL. |
Although in most cases the value is processor dependent, the value
does not vary between invocations for any particular X kind type
parameter and CLASS value.
2.8. Elemental subroutines
The modules contain the following elemental subroutines:
IEEE_GET_FLAG(FLAG,FLAG_VALUE) Get an exception flag.
IEEE_GET_HALTING_MODE(FLAG, HALTING) Get halting mode for an exception.
The initial halting mode is processor dependent. Halting is not
necessary immediate, but normal processing does not continue.
IEEE_SET_FLAG(FLAG,FLAG_VALUE) Set an exception flag.
IEEE_SET_HALTING_MODE(FLAG,HALTING) Controls continuation or halting
on exceptions. IEEE_SUPPORT_HALTING(FLAG) must be true. |
2.9. Non-elemental subroutines
The modules contain the following non-elemental subroutines:
IEEE_GET_ROUNDING_MODE(ROUND_VALUE) Get the current IEEE rounding
mode. ROUND_VALUE is of type IEEE_ROUND_TYPE.
IEEE_GET_STATUS(STATUS_VALUE) Get the current values of the set of
flags that define the current state of the floating point
environment. STATUS_VALUE is of type IEEE_STATUS_TYPE.
IEEE_SET_ROUNDING_MODE(ROUND_VALUE) Set the current IEEE rounding
mode. ROUND_VALUE is of type IEEE_ROUND_TYPE, with value
IEEE_NEAREST, IEEE_TO_ZERO, IEEE_UP, or IEEE_DOWN.
If this is invoked, IEEE_SUPPORT_ROUNDING(ROUND_VALUE,X) must be true |
for any X such that IEEE_SUPPORT_DATATYPE(X) is true. |
IEEE_SET_STATUS(STATUS_VALUE) Restore the values of the set of flags
that define the current state of the floating point environment
(usually the floating point status register). STATUS_VALUE is of type
IEEE_STATUS_TYPE and has been set by a call of IEEE_GET_STATUS.
2.10. Transformational function
The modules contain the following transformational function:
IEEE_SELECTED_REAL_KIND ( [P,] [R]) As for SELECTED_REAL_KIND but gives
an IEEE kind.
3. EDITS TO THE DRAFT STANDARD (N1176, March 1996)
xvi/16. Add 'A module may be intrinsic (defined by the standard) or
nonintrinsic (defined by Fortran 90 code).'
19/6. After 'procedures,' add 'modules,'.
131/33. Add: 'If any exception (15) is signaling, the processor shall
issue a warning on the unit identified by * in a WRITE statement,
indicating which exceptions are signaling.'.
186/17. Add 'An <> is defined by the standard.
A <> is defined by Fortran 90 code.
187/22-23. Change to
R1107 use-stmt is USE [,module-nature::] module-name [, rename-list]
or USE [,module-nature::] module-name, ONLY : [only-list]
R1107a module-nature is INTRINSIC
or NON_INTRINSIC
Constraint: If is INTRINSIC, module-name must be the name
of an intrinsic module.
Constraint: If is NON_INTRINSIC, module-name must be the name
of an nonintrinsic module.
187/31+. A without a provides access either
to an intrinsic or to a nonintrinsic module. If the is
the name of both an intrinsic and a nonintrinsic module, the
nonintrinsic module is accessed.
228/36. Change '.' to ', unless IEEE_LEVEL of one of the intrinsic modules
IEEE_ARITHMETIC and IEEE_SUBSET (Section 15) is accessible and there is
support for an infinite or a NaN result, as appropriate. If an infinite
result is returned, the flag IEEE_OVERFLOW or IEEE_DIVIDE_BY_ZERO shall
signal; if a NaN result is returned, the flag IEEE_INVALID shall
signal. If all results are normal, the exception flags must have the
same status as when the intrinsic procedure was invoked.'
292+. Add
<<15. Intrinsic modules for support of exceptions and IEEE arithmetic>>
The intrinsic modules IEEE_ARITHMETIC and IEEE_SUBSET provide support
for the floating point exceptions associated with overflow and divide
by zero for real or complex data with any kind parameter. If the type
and kind parameter implements IEEE arithmetic (IEEE 754-1985), the
modules provide more extensive support, including the exceptions
invalid, underflow, and inexact. There are inquiry functions that
permit the extent of support of IEEE 754-1985 to be determined.
Both modules contain the constant IEEE_LEVEL of type default integer.
It has the value 1 in IEEE_SUBSET and the value 2 in IEEE_ARITHMETIC.
The extent of IEEE support must be no less for IEEE_ARITHMETIC than for
IEEE_SUBSET. If a scoping unit has access to IEEE_LEVEL of
IEEE_ARITHMETIC, the scoping unit must provide the corresponding level
of support. If a scoping unit has access to IEEE_LEVEL of IEEE_SUBSET
and does not have access to IEEE_LEVEL of IEEE_ARITHMETIC, the scoping
unit must provide the subset level of support. Execution may be faster
with the subset. If a scoping unit has access to neither IEEE_LEVEL,
the level of support is processor determined, and need not include
support for any exceptions. Following execution of code in such a
scoping unit, the values of the flags are processor determined.
Note: A processor with no support for IEEE data need not supply the |
elemental functions of 15.8.2. |
<<15.1 Derived data types defined in the module>>
The module contains four data types, whose components are private.
No operation is defined for any of them and only intrinsic assignment
is available for them. They are:
1. TYPE(IEEE_FLAG_TYPE), for identifying a particular exception flag. Its
only possible values are those of constants defined in the module:
IEEE_INVALID, IEEE_OVERFLOW, IEEE_DIVIDE_BY_ZERO, IEEE_USUAL,
IEEE_UNDERFLOW, IEEE_INEXACT, and IEEE_ALL.
2. TYPE(IEEE_CLASS_TYPE), for identifying a class of floating-point values.
Its only possible values are those of constants defined in the
module: IEEE_SIGNALING_NAN, IEEE_QUIET_NAN, IEEE_NEGATIVE_INF,
IEEE_NEGATIVE_NORMAL, IEEE_NEGATIVE_DENORMAL, IEEE_NEGATIVE_ZERO,
IEEE_POSITIVE_ZERO, IEEE_POSITIVE_DENORMAL, IEEE_POSITIVE_NORMAL,
IEEE_POSITIVE_INF.
3. TYPE(IEEE_ROUND_TYPE), for identifying a particular rounding mode. Its
only possible values are those of constants defined in the module:
IEEE_NEAREST, IEEE_TO_ZERO, IEEE_UP, IEEE_DOWN, and IEEE_OTHER.
4. TYPE(IEEE_STATUS_TYPE), for saving the current floating point status.
<<15.2 The exceptions>>
The exceptions are:
IEEE_OVERFLOW
This exception occurs when the result for an intrinsic real operation
has a very large processor-dependent absolute value, or the real or
imaginary part of the result for an intrinsic complex operation has a
very large processor-dependent absolute value.
IEEE_DIVIDE_BY_ZERO
This exception occurs when a real or complex division has a nonzero
numerator and a zero denominator.
IEEE_INVALID
This exception occurs when a real or complex operation is invalid.
IEEE_UNDERFLOW
This exception occurs when the result for an intrinsic real operation
has a very small processor-dependent absolute value, or the real or
imaginary part of the result for an intrinsic complex operation has a
very small processor-dependent absolute value.
IEEE_INEXACT
This exception occurs when the result of a real or complex operation
is not exact.
IEEE_USUAL
This exception occurs whenever any of the exceptions IEEE_OVERFLOW,
IEEE_DIVIDE_BY_ZERO, and IEEE_INVALID occur.
IEEE_ALL
This exception occurs whenever any of the exceptions IEEE_OVERFLOW,
IEEE_DIVIDE_BY_ZERO, IEEE_INVALID, IEEE_UNDERFLOW, IEEE_INEXACT occur.
Each exception has a flag whose value is either quiet or signaling. The
value may be determined by the function IEEE_GET_FLAG. Its initial
value is quiet and it signals when the associated exception occurs. Its
status may also be changed by the subroutine IEEE_SET_FLAG or the
subroutine IEEE_SET_STATUS. Once signaling, it remains signaling unless
set quiet by an invocation of the subroutine IEEE_SET_FLAG or the
subroutine IEEE_SET_STATUS. If any exception is signaling when the program
terminates, the processor shall issue a warning on the unit identified
by * in a WRITE statement, indicating which conditions are signaling.
If a flag is signaling on entry to a pure procedure, the flag shall not
be set to quiet unless it is reset before return.
If an intrinsic procedure executes normally, the values of the flags |
IEEE_OVERFLOW, IEEE_DIVIDE_BY_ZERO, IEEE_INVALID, and IEEE_USUAL shall |
be as on entry to the procedure, even if one or more signals during the |
calculation. If a result is too large for the intrinsic to handle, |
IEEE_OVERFLOW shall signal. If a requirement of the standard is not met |
(for example, LOG(-1.0)), IEEE_INVALID may signal. These rules also |
apply to the evaluation of specification expressions on entry to a |
procedure, to format processing, and to an intrinsic operation that is |
implemented with software. |
In a sequence of statements that contains no invocations of |
IEEE_GET_FLAG, IEEE_SET_FLAG, IEEE_GET_STATUS, or IEEE_SET_STATUS, if |
the execution of a process would cause an exception to
signal but after execution of the sequence no value of a variable
depends on the process, whether the exception is signaling is processor
dependent. For example, when Y has the value zero, whether the code
X = 1.0/Y
X = 3.0
signals IEEE_DIVIDE_BY_ZERO is processor dependent.
An exception must not signal if this could arise only during
execution of a process further to those required or permitted by the
standard. For example, the statement
IF (F(X)>0.) Y = 1.0/Z
must not signal IEEE_DIVIDE_BY_ZERO when both F(X) and Z are zero and the
statement
WHERE(A>0.0) A = 1.0/A
must not signal IEEE_DIVIDE_BY_ZERO. On the other hand, when
X has the value 1.0 and Y has the value 0.0, the expression
X>0.00001 .OR. X/Y>0.00001
is permitted to cause the signaling of IEEE_DIVIDE_BY_ZERO.
Note: It is intended that implementations be free to use code motion
techniques except across an invocation of IEEE_GET_FLAG, |
IEEE_SET_FLAG, IEEE_GET_STATUS, or IEEE_SET_STATUS. |
The processor need not support IEEE_INVALID, IEEE_UNDERFLOW, and
IEEE_INEXACT. If an exception is not supported, its flag is always
quiet. The function IEEE_SUPPORT_FLAG may be used to inquire whether a
particular flag is supported.
<<15.3 The rounding modes>>
IEEE 754-1985 specifies four rounding modes:
IEEE_NEAREST rounds the exact result to the nearest representable value.
IEEE_TO_ZERO rounds the exact result towards zero to the next
representable value.
IEEE_UP rounds the exact result towards +infinity to the next
representable value.
IEEE_DOWN rounds the exact result towards -infinity to the next
representable value.
The function IEEE_GET_ROUNDING_MODE may be used to inquire which
rounding mode is in operation. Its value is one of the above four
or IEEE_OTHER if the rounding mode does not conform to IEEE 754-1985.
If the processor supports the alteration of the rounding mode during
execution, the subroutine IEEE_SET_ROUNDING_MODE may be used to alter
it. The function IEEE_SUPPORT_ROUNDING may be used to inquire whether
this facility is available for a particular mode.
<<15.4 Halting>>
If the processor supports the ability to control during program
execution whether to abort or continue execution after an exception,
such control may be exercised by invocation of the subroutine
IEEE_SET_HALTING_MODE. Halting is not precise and may occur any time
after the exception has occurred. The function IEEE_SUPPORT_HALTING may
be used to inquire whether this facility is available.
<<15.5 The floating point status>>
The values of all the supported flags for exceptions, rounding mode,
and halting may be saved in a scalar variable of type
TYPE(IEEE_STATUS_TYPE) with the function IEEE_GET_STATUS and restored with
the subroutine IEEE_SET_STATUS. There are no facilities for finding the
values of particular flags held within such a variable.
Note. Some processors hold all these flags in a floating point
status register that can be saved and restored as a whole much
faster than all individual flags can be saved and restored. These
procedures are provided to exploit this feature.
<<15.6 Exceptional values>>
IEEE 754-1985 specifies the following exceptional floating point values:
Denormalized values have very small absolute values and lowered precision.
Infinite values (+Inf and -Inf) are created by overflow or division by zero.
Not-a-Number (NaN) values are undefined values or values created by
an invalid operation.
The functions IEEE_IS_FINITE, IEEE_IS_NAN, IEEE_IS_NEGATIVE, and
IEEE_IS_NORMAL are provided to test whether a value is finite, NaN,
negative, or normal. The function IEEE_VALUE is provided to generate an
IEEE number of any class, including an infinity or a NaN. The
functions IEEE_SUPPORT_DENORMAL, IEEE_SUPPORT_DIVIDE, IEEE_SUPPORT_INF,
and IEEE_SUPPORT_NAN may be used to inquire whether this facility is
available for a particular kind of real.
<<15.7 IEEE arithmetic>>
The function IEEE_SUPPORT_DATATYPE may be used to inquire whether IEEE
arithmetic is available for a particular kind of real. Complete
conformance with the IEEE standard is not required, but the normalized
numbers must be exactly those of IEEE single or IEEE double; the
arithmetic operators must be implemented with at least one of the IEEE
rounding modes; and the functions copysign, scalb, logb, nextafter, and
unordered must be provided by the functions IEEE_COPY_SIGN, IEEE_SCALB,
IEEE_LOGB, IEEE_NEXT_AFTER, and IEEE_UNORDERED.
IEEE 754-1985 specifies a square root function that returns -0.0 for the
square root of -0.0. The function IEEE_SQRT is provided for this and the
function IEEE_SUPPORT_SQRT may be used to inquire whether this facility
is available for a particular kind of real.
The inquiry function IEEE_SUPPORT_STANDARD is provided to inquire whether the
processor supports all the IEEE facilities defined in this standard for
a particular kind of real.
<<15.8 Tables of the procedures>>
In this section, the procedures are tabulated with the names of their
arguments and a short description.
<<15.8.1 Inquiry functions>>
IEEE_SUPPORT_DATATYPE([X]) Inquire if the processor supports IEEE arithmetic.
IEEE_SUPPORT_DENORMAL([X]) Inquire if the processor supports IEEE gradual
underflow.
IEEE_SUPPORT_DIVIDE([X]) Inquire if the processor supports IEEE divide.
IEEE_SUPPORT_FLAG(FLAG [, X]) Inquire if the processor supports an exception.
IEEE_SUPPORT_HALTING(FLAG) Inquire if the processor supports control
of halting after an exception.
IEEE_SUPPORT_INF([X]) Inquire if processor supports the IEEE infinity.
IEEE_SUPPORT_NAN([X]) Inquire if processor supports the IEEE Not-A-Number.
IEEE_SUPPORT_ROUNDING(ROUND_VALUE [, X]) Inquire if processor supports
a particular rounding mode.
IEEE_SUPPORT_SQRT([X]) Inquire if the processor supports IEEE square root.
IEEE_SUPPORT_STANDARD([X]) Inquire if processor supports all IEEE facilities.
<<15.8.2 Elemental functions>>
IEEE_CLASS(X) IEEE class.
IEEE_COPY_SIGN(X,Y) IEEE copysign function.
IEEE_IS_FINITE(X) Determine if value is finite.
IEEE_IS_NAN(X) Determine if value is IEEE Not-a-Number.
IEEE_IS_NORMAL(X) Whether a value is normal, that is, neither an
Infinity, a NaN, nor denormalized.
IEEE_LOGB(X) Unbiased exponent in the IEEE floating point format.
IEEE_NEXT_AFTER(X,Y) Returns the next representable neighbor of X in the
direction toward Y.
IEEE_SCALB(X,I) Returns X * 2**I.
IEEE_SQRT(X) Square root as defined in the IEEE standard.
IEEE_UNORDERED(X,Y) IEEE unordered function. True if X or Y is a NaN
and false otherwise.
IEEE_VALUE(X, CLASS) Generate an IEEE value.
<<15.8.3 Elemental subroutines>>
IEEE_GET_FLAG(FLAG,FLAG_VALUE) Get an exception flag.
IEEE_GET_HALTING_MODE(FLAG, HALTING) Get halting mode for an exception.
IEEE_SET_FLAG(FLAG,FLAG_VALUE) Set an exception flag.
IEEE_SET_HALTING_MODE(FLAG,HALTING) Controls continuation or halting on
exceptions.
<<15.8.4 Non-elemental subroutines>>
IEEE_GET_ROUNDING_MODE(ROUND_VALUE) Get the current IEEE rounding mode.
IEEE_GET_STATUS(STATUS_VALUE) Get the current state of the floating point
environment.
IEEE_SET_ROUNDING_MODE(ROUND_VALUE) Set the current IEEE rounding mode.
IEEE_SET_STATUS(STATUS_VALUE) Restore the state of the floating point
environment.
<<15.9 Specifications of the procedures>>
IEEE_CLASS(X)
Description. IEEE class function.
Class. Elemental function.
Argument. X shall be of type real and such that
IEEE_SUPPORT_DATATYPE(X) has the value true.
Result Characteristics. TYPE(IEEE_CLASS_TYPE).
Result Value. The result value is one of: IEEE_SIGNALING_NAN,
IEEE_QUIET_NAN, IEEE_NEGATIVE_INF, IEEE_NEGATIVE_NORMAL,
IEEE_NEGATIVE_DENORMAL, IEEE_NEGATIVE_ZERO, IEEE_POSITIVE_ZERO,
IEEE_POSITIVE_DENORMAL, IEEE_POSITIVE_NORMAL, IEEE_POSITIVE_INF.
Neither of the values IEEE_SIGNALING_NAN and IEEE_QUIET_NAN shall be
returned unless IEEE_SUPPORT_NAN(X) has the value true. Neither of
the values IEEE_NEGATIVE_INF and IEEE_POSITIVE_INF shall be returned
unless IEEE_SUPPORT_INF(X) has the value true. Neither of the
values IEEE_NEGATIVE_DENORMAL and IEEE_POSITIVE_DENORMAL shall be
returned unless IEEE_SUPPORT_DENORMAL(X) has the value true.
Example. IEEE_CLASS(-1.0) has the value IEEE_NEGATIVE_NORMAL.
IEEE_COPY_SIGN(X,Y)
Description. IEEE copysign function.
Class. Elemental function.
Arguments. The arguments shall be of type real and such that both
IEEE_SUPPORT_DATATYPE(X) and IEEE_SUPPORT_DATATYPE(Y) have the value true.
Result Characteristics. Same as X.
Result Value. The result has the value of X with the sign of Y.
This is true even for IEEE special values, such as NaN and Inf (on
processors supporting such values).
Examples. The value of IEEE_COPY_SIGN(X,1.0) is ABS(X) even when X is
NaN. The value of IEEE_COPY_SIGN(-X,1.0) is X copied with its sign
reversed, not 0-x; the distinction is germane when X is +0, -0, or
NaN.
IEEE_GET_FLAG(FLAG,FLAG_VALUE)
Description. Get an exception flag.
Class. Elemental subroutine.
Arguments.
FLAG shall be of type TYPE(IEEE_FLAG_TYPE). It is an INTENT(IN)
argument and specifies the IEEE flag to be obtained.
FLAG_VALUE shall be of type default logical. It is an INTENT(OUT)
argument and returns:
Case (i): If the value of FLAG is IEEE_INVALID, IEEE_OVERFLOW,
IEEE_DIVIDE_BY_ZERO, IEEE_UNDERFLOW, or IEEE_INEXACT,
the result value is true if the corresponding exception flag
is signaling and is false otherwise.
Case (ii): If the value of FLAG is IEEE_USUAL, the result value is true if
the invalid, divide_by_zero, or overflow flag is signaling and
is false otherwise.
Case (iii): If the value of FLAG is IEEE_ALL, the result value is true if
any flag is signaling and is false otherwise.
Example. Following CALL IEEE_GET_FLAG(IEEE_OVERFLOW,FLAG_VALUE),
FLAG_VALUE is true if the overflow flag is signaling and is false if it
is quiet.
IEEE_GET_HALTING_MODE(FLAG,HALTING)
Description. Get halting mode for an exception.
Class. Elemental subroutine.
Arguments.
FLAG shall be of type TYPE(IEEE_FLAG_TYPE). It is an INTENT(IN)
argument and specifies the IEEE flag. It shall have one of the
values IEEE_INVALID, IEEE_OVERFLOW, IEEE_DIVIDE_BY_ZERO,
IEEE_UNDERFLOW, and IEEE_INEXACT.
HALTING shall be scalar and of type default logical. It is of
INTENT(OUT). The value is true if the exception specified
by FLAG will cause halting. Otherwise, the value is false.
Example. To store the halting mode for overflow, do a calculation
without halting, and restore the halting mode later:
USE, INTRINSIC :: IEEE_ARITHMETIC
LOGICAL HALTING
:
CALL IEEE_GET_HALTING_MODE(IEEE_OVERFLOW,HALTING) ! Store halting mode
CALL IEEE_SET_HALTING_MODE(IEEE_OVERFLOW,.FALSE.) ! No halting
: ! calculation without halting
CALL IEEE_SET_HALTING_MODE(IEEE_OVERFLOW,HALTING) ! Restore halting mode
IEEE_GET_ROUNDING_MODE(ROUND_VALUE)
Description. Get the current IEEE rounding mode.
Class. Subroutine.
Argument. ROUND_VALUE shall be scalar of type TYPE(IEEE_ROUND_TYPE). It
is an INTENT(OUT) argument and returns the floating point rounding
mode, with value IEEE_NEAREST, IEEE_TO_ZERO, IEEE_UP, or IEEE_DOWN
if one of the IEEE modes is in operation and IEEE_OTHER otherwise.
Example. To store the rounding mode, do a calculation
with round to nearest, and restore the rounding mode later:
USE, INTRINSIC :: IEEE_ARITHMETIC
TYPE(IEEE_ROUND_TYPE) ROUND_VALUE
:
CALL IEEE_GET_ROUNDING_MODE(ROUND_VALUE) ! Store the rounding mode
CALL IEEE_SET_ROUNDING_MODE(IEEE_NEAREST)
: ! calculation with round to nearest
CALL IEEE_SET_ROUNDING_MODE(ROUND_VALUE) ! Restore the rounding mode
Note. The result can legally be used only in an IEEE_SET_ROUNDING_MODE
invocation.
IEEE_GET_STATUS(STATUS_VALUE)
Description. Get the current values of the set of flags that define
the current floating point status, including all the exception
flags.
Class. Subroutine.
Arguments. STATUS_VALUE shall be scalar of type
TYPE(IEEE_STATUS_TYPE). It is an INTENT(OUT) argument and returns the
floating point status.
Example. To store all the exception flags, do a calculation
involving exception handling, and restore them later:
USE, INTRINSIC :: IEEE_ARITHMETIC
TYPE(IEEE_STATUS_TYPE) STATUS_VALUE
:
CALL IEEE_GET_STATUS(STATUS_VALUE) ! Get the flags
CALL IEEE_SET_FLAG(IEEE_ALL,.FALSE.) ! Set the flags quiet.
: ! calculation involving exception handling
CALL IEEE_SET_STATUS(STATUS_VALUE) ! Restore the flags
Note. The result can be used only in an IEEE_SET_STATUS invocation.
IEEE_IS_FINITE(X)
Description. Whether a value is finite.
Class. Elemental function.
Argument. X shall be of type real and such that IEEE_SUPPORT_DATATYPE(X)
has the value true.
Result Characteristics. Default logical scalar.
Result Value. The result has the value true if the value of X is
finite, that is, IEEE_CLASS(X) has one of the values
IEEE_NEGATIVE_NORMAL, IEEE_NEGATIVE_DENORMAL, IEEE_NEGATIVE_ZERO,
IEEE_POSITIVE_ZERO, IEEE_POSITIVE_DENORMAL, and IEEE_POSITIVE_NORMAL;
otherwise, the result has the value false.
Example. IEEE_IS_FINITE(1.0) has the value true.
IEEE_IS_NAN(X)
Description. Whether a value is IEEE Not-a-Number.
Class. Elemental function.
Argument. X shall be of type real and such that IEEE_SUPPORT_NAN(X)
has the value true.
Result Characteristics. Default logical scalar.
Result Value. The result has the value true if the value of X is an
IEEE NaN; otherwise, it has the value false.
Example. IEEE_IS_NAN(IEEE_SQRT(-1.0)) has the value true.
IEEE_IS_NEGATIVE(X)
Description. Whether a value is negative.
Class. Elemental function.
Argument. X shall be of type real and such that IEEE_SUPPORT_DATATYPE(X)
has the value true.
Result Characteristics. Default logical scalar.
Result Value. The result has the value true if CLASS(X) has one of
the values IEEE_NEGATIVE_NORMAL, IEEE_NEGATIVE_DENORMAL,
IEEE_NEGATIVE_ZERO and IEEE_NEGATIVE_INF; otherwise, the result has
the value false.
Example. IEEE_IS_NEGATIVE(0.0)) has the value false.
IEEE_IS_NORMAL(X)
Description. Whether a value is normal, that is, neither an
Infinity, a NaN, nor denormalized.
Class. Elemental function.
Argument. X shall be of type real and such that IEEE_SUPPORT_DATATYPE(X)
has the value true.
Result Characteristics. Default logical scalar.
Result Value. The result has the value true if CLASS(X) has one of
the values IEEE_NEGATIVE_NORMAL, IEEE_NEGATIVE_ZERO,
IEEE_POSITIVE_ZERO and IEEE_POSITIVE_NORMAL; otherwise, the result has
the value false.