X3J3/96-090r1
Date: May 23, 1996
To: X3J3
From: John K. Reid
Subject: Draft TR for Floating-Point Exception Handling
DRAFT TECHNICAL REPORT FOR FLOATING-POINT EXCEPTION HANDLING
23 May 1996
0. NOTES
This is a draft Technical Report using procedures in two modules for
exception handling. I will explain the progress since the version
of 8 May 1996.
There was no objection to the changes of notes 1-6 of the version of
May 8. Both Weber and X3J3 commented on note 7 and so I have made
significant changes to the text for 15.2. I have decided not to act on
note 8 (name changes). X3J3 strongly opposes any name changes.
Einarsson is opposed. Clodius wants other changes. There has been no
opposition to adding IEEE_RINT (note 9).
There has been significant general opposition from Weber. I have made
changes to address some of his comments, but addressing all of them
would involve a major redesign and there appears to be no support for
this from elsewhere. Indeed X3J3 spent some time considering his
comments and is strongly opposed.
These are the changes since May 8:
1. IEEE_RINT has been added.
2. The global change 'processor determined' => 'processor dependent',
requested by X3J3 has been made.
3. The text for 15.2 has been altered in response to comments from
Weber and X3J3 (note 7).
Please check this document carefully and soon. Time is running out.
I want the DB to be able to present a polished document to WG5 in
Dresden.
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 dependent, and need not include |
support for any exceptions. Following execution of code in such a
scoping unit, the values of the flags are processor dependent. |
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_RINT(X) Round to an integer value according to the current rounding |
mode. |
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 dependent, and need not include |
support for any exceptions. Following execution of code in such a
scoping unit, the values of the flags are processor dependent. |
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 to signaling before return. |
In a scoping unit has access to IEEE_LEVEL of IEEE_ARITHMETIC or |
IEEE_SUBSET, |
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 may 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.
Note: An implementation is permitted to provide two versions of an |
intrinsic procedure, one suitable for a call from a scoping unit with |
access to IEEE_LEVEL of IEEE_ARITHMETIC or IEEE_SUBSET and one for |
other cases. |
In a sequence of statements that contains no invocations of IEEE_GET_FLAG, |
IEEE_SET_FLAG, IEEE_GET_STATUS, IEEE_SET_HALTING, 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. Another example is |
the following: |
REAL, PARAMETER :: X=0.0, Y=6.0 |
: |
IF (1.0/X == Y) PRINT *,'Hello world' |
where processor is permitted to discard the IF statement since the |
logical expression can never be true and no value of a variable |
depends on it. |
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, IEEE_SET_HALTING, or IEEE_SET_STATUS. |
Code motion across a procedure boundary such as in the code |
DO I = 1, 100 |
CALL HUGO(X) |
A=B+C ! A, B, C are all local variables |
END DO |
is therefore permitted only if the processor is able to verify that |
the invoked procedure contains no invocation of IEEE_GET_FLAG, |
IEEE_SET_FLAG, IEEE_GET_STATUS, IEEE_SET_HALTING, 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_RINT(X) Round to an integer value according to the current rounding |
mode. |
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.
.
Example. IEEE_IS_NORMAL(IEEE_SQRT(-1.0)) has the value false.
IEEE_LOGB(X)
Description. Unbiased exponent in the IEEE floating point format.
Class. Elemental function.
Argument. X shall be of type real and such that IEEE_SUPPORT_DATATYPE(X)
has the value true.
Result Characteristics. Same as X.
Result Value.
Case (i): If the value of X is neither zero, infinity, nor NaN,
the result has the value of the unbiased exponent of X.
Case(ii): If X==0, IEEE_DIVIDE_BY_ZERO signals and the result is
-Inf if IEEE_SUPPORT_INF(X) is true and -HUGE(X)
otherwise.
Case(iii): If X has an infinite value, the result is +Inf.
Case(iv): If X has a NaN value, the result is a NaN.
Note: Cases (iii) and (iv) cannot occur on processors that lack Inf and
NaN values.
Example. IEEE_LOGB(-1.1) has the value 0.0.
IEEE_NEXT_AFTER(X,Y)
Description. Returns the next representable neighbor of X in the
direction toward Y.
Class. Elemental function.
Arguments. The arguments shall be of type real and such that
IEEE_SUPPORT_DATATYPE(X) and IEEE_SUPPORT_DATATYPE(Y) have the value true.
Result Characteristics. Same as X.
Result Value.
Case (i): If X == Y, the result is X without any exception ever
being signaled.
Case (ii): If X /= Y, the result has the value of the next
representable neighbor of X in the direction of Y. If
either X or Y is a NaN, the result is one or the
other of the input NaNs. Overflow is signaled when X is
finite but IEEE_NEXT_AFTER(X,Y) is infinite; underflow is
signaled when IEEE_NEXT_AFTER(X,Y) is denormalized; in both
cases, IEEE_INEXACT signals.
Example. The value of IEEE_NEXT_AFTER(1.0,2.0) is 1.0+EPSILON(X).
IEEE_RINT(X) |
Description. Round to an integer value according to the current |
rounding mode. |
Class. Elemental function. |
Argument. X shall be of type real and such that |
IEEE_SUPPORT_DATATYPE(X) has the value true. |
Result Characteristics. Same as X. |
Result Value. The value of the result is the value of X rounded to |
an integer according to the current rounding mode. |
Examples. If the current rounding mode is round-to-nearest, the |
value of IEEE_RINT(1.1) is 1.0. If the current rounding mode is |
round-up, the value of IEEE_RINT(1.1) is 2.0. |
IEEE_SCALB(X,I)
Description. Returns X * 2**I.
Class. Elemental function.
Arguments.
X shall be of type real and such that IEEE_SUPPORT_DATATYPE(X)
has the value true.
I shall be of type integer.
Result Characteristics. Same as X.
Result Value.
Case (i): If X * 2**I is within range, the result has this value.
Case (ii): If X * 2**I is too large and IEEE_SUPPORT_INF(X) is true,
the result value is infinity with the sign of X.
Case (iii): If X * 2**I is too large and IEEE_SUPPORT_INF(X) is false,
the result value is SIGN(HUGE(X),X).
Example. The value of IEEE_SCALB(1.0,2) is 4.0.
IEEE_SELECTED_REAL_KIND ([P, R])
Description. Returns a value of the kind type parameter of a IEEE
real data type with decimal precision of at least P digits and a
decimal exponent range of at least R. For data objects of such a
type, IEEE_SUPPORT_DATATYPE(X) has the value true.
Class. Transformational function.
Arguments. At least one argument shall be present.
P (optional) shall be scalar and of type integer.
R (optional) shall be scalar and of type integer.
Result Characteristics. Default integer scalar.
Result Value. The result has a value equal to a value of the kind
type parameter of a IEEE real data type with decimal precision, as
returned by the function PRECISION, of at least P digits and a
decimal exponent range, as returned by the function RANGE, of at
least R, or if no such kind type parameter is available on the
processor, the result is -1 if the precision is not available, -2 if
the exponent range is not available, and -3 if neither is
available. If more than one kind type parameter value meets the
criteria, the value returned is the one with the smallest decimal
precision, unless there are several such values, in which case the
smallest of these kind values is returned.
Example. IEEE_SELECTED_REAL_KIND(6,70) has the value KIND(0.0) on a
machine that supports IEEE single precision arithmetic for its
default real approximation method.
IEEE_SET_FLAG(FLAG,FLAG_VALUE)
Description. Assign a value to an exception flag.
Class. Elemental subroutine.
Arguments.
FLAG shall be of type TYPE(IEEE_FLAG_TYPE). It is an INTENT(IN)
argument. If the value of FLAG is IEEE_INVALID, IEEE_OVERFLOW,
IEEE_DIVIDE_BY_ZERO, IEEE_UNDERFLOW, or IEEE_INEXACT,
the corresponding exception flag is assigned a value. If the value
is IEEE_USUAL, the invalid, divide_by_zero or overflow flags are all
assigned. If the value is IEEE_ALL, all the flags are all
assigned.
FLAG_VALUE shall be of type default logical. It is an INTENT(IN)
argument. If it has the value true, the flag is set to be signaling;
otherwise, the flag to set to be quiet.
Example. CALL IEEE_SET_FLAG(IEEE_OVERFLOW,.TRUE.) sets the overflow flag
to be signaling.
IEEE_SET_HALTING_MODE(FLAG,HALTING)
Description. Controls continuation or halting after an exception.
Class. Elemental subroutine. IEEE_SUPPORT_HALTING(FLAG) shall be true.
Arguments.
FLAG shall be scalar and of type TYPE(IEEE_FLAG_TYPE). It is of
INTENT(IN) and 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(IN). If the value is true, the exception specified by
FLAG will cause halting. Otherwise, execution will continue
after this exception.
Example. CALL IEEE_SET_HALTING_MODE(IEEE_DIVIDE_BY_ZERO,.TRUE.)
causes halting after a divide_by_zero exception.
Notes: Initially, the mode is for continuation. Halting is not precise
and may occur some time after the exception has occurred.
IEEE_SET_ROUNDING_MODE(ROUND_VALUE)
Description. Set the current IEEE rounding mode.
Class. Subroutine.
Argument. ROUND_VALUE shall be scalar and of type TYPE(IEEE_ROUND_TYPE).
It is an INTENT(IN) argument and specifies the mode to be set. Its value
shall be one of IEEE_NEAREST, IEEE_TO_ZERO, IEEE_UP, and IEEE_DOWN.
IEEE_SUPPORT_ROUNDING(ROUND_VALUE,X) shall be true for any X such that
IEEE_SUPPORT_DATATYPE(X) is true.
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
IEEE_SET_STATUS(STATUS_VALUE)
Description. Restore the values of the set of flags that define the
the floating point status.
Class. Subroutine.
Argument. STATUS_VALUE shall be scalar and of type
TYPE(IEEE_STATUS_TYPE). It is an INTENT(IN) argument. Its value
shall have been set in a previous invocation of IEEE_GET_STATUS.
Example. To store all the exceptions 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) ! Store the flags
CALL IEEE_SET_FLAGS(IEEE_ALL,.FALSE.) ! Set them quiet
: ! calculation involving exception handling
CALL IEEE_SET_STATUS(STATUS_VALUE) ! Restore the flags
Note: getting and setting may be expensive operations. It is the
programmer's responsibility to do it when necessary to assure correct
results.
IEEE_SQRT(X)
Description. Square root as defined in the IEEE standard.
Class. Elemental function.
Argument. X shall be of type real and such that IEEE_SUPPORT_SQRT(X)
has the value true.
Result characteristics. Same as X.
Result value. The result has the value of the square-root of X as
defined in the IEEE Standard.
Example. IEEE_SQRT(-0.0) has the value -0.0.
Note: On most IEEE processors, SQRT is probably the same as IEEE_SQRT.
However, processors without adequate hardware support may choose to
return different values in hard cases, in which case a careful
programmer may wish to use IEEE_SQRT for safety.
IEEE_SUPPORT_DATATYPE([X])
Description. Inquire if the processor supports IEEE arithmetic.
Class. Inquiry function.
Argument. X shall be scalar and of type real.
Result Characteristics. Default logical scalar.
Result Value. The result has the value true if the processor supports
IEEE arithmetic for all reals (X absent) or for real variables
of the same kind type parameter as X; otherwise, it has the value
false. 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.
Example. IEEE_SUPPORT_DATATYPE(1.0) has the value .TRUE. if default
reals are implemented as in the IEEE standard except that
underflowed values flush to 0.0 instead of being denormal.
IEEE_SUPPORT_DENORMAL([X])
Description. Inquire if the processor supports IEEE gradual underflow.
Class. Inquiry function.
Argument. X (optional) shall of type real and such that
IEEE_SUPPORT_DATATYPE(X) has the value true. It may be scalar or
array valued.
Result Characteristics. Default logical scalar.
Result Value. The result has the value true if the processor supports
IEEE gradual underflow for all reals (X absent) or for real variables
of the same kind type parameter as X; otherwise, it has the value false.
Example. IEEE_SUPPORT_DENORMAL(X) has the value true if the processor
supports gradual underflow for X.
IEEE_SUPPORT_DIVIDE([X])
Description. Inquire if the processor supports IEEE divide.
Class. Inquiry function.
Argument. X (optional) shall of type real and such that
IEEE_SUPPORT_DATATYPE(X) has the value true. It may be scalar or
array valued.
Result Characteristics. Default logical scalar.
Result Value. The result has the value true if the processor supports
IEEE divide for all reals (X absent) or for real variables
of the same kind type parameter as X; otherwise, it has the value false.
Example. IEEE_SUPPORT_DIVIDE(X) has the value true if the processor
supports IEEE divide for X.
IEEE_SUPPORT_FLAG(FLAG [, X])
Description. Inquire if the processor supports an exception.
Class. Inquiry function.
Arguments.
FLAG shall be scalar and of type TYPE(IEEE_FLAG_TYPE). Its value
shall be one of IEEE_INVALID, IEEE_OVERFLOW, IEEE_DIVIDE_BY_ZERO,
IEEE_USUAL, IEEE_UNDERFLOW, IEEE_INEXACT, and IEEE_ALL.
X (optional) shall of type real. It may be scalar or array valued.
Result Characteristics. Default logical scalar.
Result Value. The result has the value true if the processor
supports detection of the specified exception for all reals (X
absent) or for real variables of the same kind type parameter as X;
otherwise, it has the value false.
Example. IEEE_SUPPORT_FLAG(IEEE_ALL) has the value true if the processor
supports all the exceptions.
IEEE_SUPPORT_HALTING(FLAG)
Description. Inquire if the processor supports the ability to control
during program execution whether to abort or continue execution
after an exception.
Class. Inquiry function.
Arguments.
FLAG shall be of type TYPE(IEEE_FLAG_TYPE). It is an INTENT(IN)
argument. Its value shall be one of IEEE_INVALID, IEEE_OVERFLOW,
IEEE_DIVIDE_BY_ZERO, IEEE_UNDERFLOW, and IEEE_INEXACT.
Result Characteristics. Default logical scalar.
Result Value. The result has the value true if the processor
supports the ability to control during program execution whether to
abort or continue execution after the exception specified by FLAG;
otherwise, it has the value false.
Example. IEEE_SUPPORT_HALTING(IEEE_OVERFLOW) has the value true if the
processor supports control of halting after an overflow.
IEEE_SUPPORT_INF([X])
Description. Inquire if processor supports the IEEE infinity facility.
Class. Inquiry function.
Argument. X (optional) shall of type real and such that
IEEE_SUPPORT_DATATYPE(X) has the value true. It may be scalar or
array valued.
Result Characteristics. Default logical scalar.
Result Value. The result has the value true if the processor supports
IEEE infinities (positive and negative) for all reals (X absent) or
for real variables of the same kind type parameter as X; otherwise,
it has the value false.
Example. IEEE_SUPPORT_INF(X) has the value true if the processor
supports IEEE infinities for X.
IEEE_SUPPORT_NAN([X])
Description. Inquire if processor supports the IEEE Not-A-Number
facility.
Class. Inquiry function.
Argument. X (optional) shall of type real and such that
IEEE_SUPPORT_DATATYPE(X) has the value true. It may be scalar or
array valued.
Result Characteristics. Default logical scalar.
Result Value. The result has the value true if the processor
supports IEEE NaNs for all reals (X absent) of for real variables of
the same kind type parameter as X; otherwise, it has the value false.
Example. IEEE_SUPPORT_NAN(X) has the value true if the processor
supports IEEE NaNs for X.
IEEE_SUPPORT_ROUNDING(ROUND_VALUE [,X])
Description. Inquire if processor supports a particular rounding
mode for IEEE kinds of reals.
Class. Inquiry function.
Argument. ROUND_VALUE shall be of type TYPE(IEEE_ROUND_TYPE) and value
one of IEEE_NEAREST, IEEE_TO_ZERO, IEEE_UP, and IEEE_DOWN.
Result Characteristics. Default logical scalar.
Result Value. The result has the value true if the processor
supports the IEEE rounding mode defined by ROUND_VALUE for all reals
(X absent) of for real variables of the same kind type parameter as
X; otherwise, it has the value false. Here, support shall include the
ability to change the mode by CALL IEEE_SET_ROUNDING(ROUND_VALUE).
Example. IEEE_SUPPORT_ROUNDING(IEEE_TO_ZERO) has the value true if the
processor supports rounding to zero for all reals.
IEEE_SUPPORT_SQRT([X])
Description. Inquire if the processor supports IEEE square root.
Class. Inquiry function.
Argument. X (optional) shall of type real and such that
IEEE_SUPPORT_DATATYPE(X) has the value true. It may be scalar or
array valued.
Result Characteristics. Default logical scalar.
Result Value. The result has the value true if the processor supports
IEEE square root for all reals (X absent) of for real variables of the
same kind type parameter as X; otherwise, it has the value false.
Example. IEEE_SUPPORT_SQRT(X) has the value true if the processor
supports IEEE square root for X.
IEEE_SUPPORT_STANDARD([X])
Description. Inquire if processor supports all the IEEE facilities
defined in this standard.
Class. Inquiry function.
Argument. X (optional) shall of type real. It may be scalar or
array valued.
Result Characteristics. Default logical scalar.
Result Value.
Case (i): If X is absent, the result has the value true if the
results of all the functions IEEE_SUPPORT_DATATYPE(),
IEEE_SUPPORT_DENORMAL(), IEEE_SUPPORT_DIVIDE(),
IEEE_SUPPORT_FLAG(FLAG) for valid FLAG, IEEE_SUPPORT_HALTING(FLAG)
for valid FLAG, IEEE_SUPPORT_INF(), IEEE_SUPPORT_NAN(),
IEEE_SUPPORT_ROUNDING(ROUND_VALUE) for valid ROUND_VALUE, and
IEEE_SUPPORT_SQRT() are all true; otherwise, the result has the value
false.
Case (ii): If X is present, the result has the value true if the
results of all the functions IEEE_SUPPORT_DATATYPE(X),
IEEE_SUPPORT_DENORMAL(X), IEEE_SUPPORT_DIVIDE(X),
IEEE_SUPPORT_FLAG(FLAG,X) for valid FLAG, IEEE_SUPPORT_HALTING(FLAG)
for valid FLAG, IEEE_SUPPORT_INF(X), IEEE_SUPPORT_NAN(X),
IEEE_SUPPORT_ROUNDING(ROUND_VALUE,X) for valid ROUND_VALUE, and
IEEE_SUPPORT_SQRT(X) are all true; otherwise, the result has the value
false.
Example. IEEE_SUPPORT_STANDARD() has the value false if the processor
supports both IEEE and non-IEEE kinds of reals.
IEEE_UNORDERED(X,Y)
Description. IEEE unordered function. True if X or Y is a NaN.
and false otherwise.
Class. Elemental function.
Arguments. The arguments shall be of type real and such that
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 true if X or Y is a NaN
or both are NaNs; otherwise, it has the value false.
Example. IEEE_UNORDERED(0.0,IEEE_SQRT(-1.0)) has the value true.
IEEE_VALUE(X,CLASS)
Description. Generate an IEEE value.
Class. Elemental function.
Arguments.
X shall be of type real and such that IEEE_SUPPORT_DATATYPE(X) has
the value true.
CLASS shall be of type TYPE(IEEE_CLASS_TYPE). The value of 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.
Result Characteristics. Same as X.
Result Value. The result value is an IEEE value as specified by CLASS.
Although in most cases the value is processor dependent, the value
shall not vary between invocations for any particular X kind type
parameter and CLASS value.
Example. IEEE_VALUE(1.0,IEEE_NEGATIVE_INF) has the value -Infinity.
<<15.10 Examples>>
Example 1:
MODULE DOT
! Module for dot product of two real arrays of rank 1.
USE, INTRINSIC :: IEEE_ARITHMETIC
LOGICAL MATRIX_ERROR
INTERFACE OPERATOR(.dot.)
MODULE PROCEDURE MULT
END INTERFACE
CONTAINS
REAL FUNCTION MULT(A,B)
REAL, INTENT(IN) :: A(:),B(:)
INTEGER I
LOGICAL OVERFLOW,OLD_OVERFLOW
IF (SIZE(A)/=SIZE(B)) THEN
MATRIX_ERROR = .TRUE.
RETURN
END IF
CALL IEEE_GET_FLAG(IEEE_OVERFLOW,OLD_OVERFLOW)
CALL IEEE_SET_FLAG(IEEE_OVERFLOW,.FALSE.)
MULT = 0.0
DO I = 1, SIZE(A)
MULT = MULT + A(I)*B(I)
END DO
CALL IEEE_GET_FLAG(IEEE_OVERFLOW,OVERFLOW)
IF (OVERFLOW) THEN
MATRIX_ERROR = .TRUE.
ELSE
IF(OLD_OVERFLOW) CALL IEEE_SET_FLAG(IEEE_OVERFLOW,.TRUE.)
END IF
END FUNCTION MULT
END MODULE DOT
This module provides the dot product of two real arrays of rank 1. If
the sizes of the arrays are different, an immediate return occurs with
MATRIX_ERROR true. If OVERFLOW occurs during the actual calculation,
the overflow flag will signal and MATRIX_ERROR will be true.
Example 2:
USE, INTRINSIC :: IEEE_ARITHMETIC
TYPE(IEEE_STATUS_TYPE) STATUS_VALUE
LOGICAL FLAG_VALUE
:
CALL IEEE_GET_STATUS(STATUS_VALUE)
CALL IEEE_SET_FLAG(IEEE_USUAL,.FALSE.)
! First try the "fast" algorithm for inverting a matrix:
MATRIX1 = FAST_INV(MATRIX) ! This must not alter MATRIX.
CALL IEEE_GET_FLAG(IEEE_USUAL,FLAG_VALUE)
IF (FLAG_VALUE) THEN
! "Fast" algorithm failed; try "slow" one:
CALL IEEE_SET_FLAG(IEEE_USUAL,.FALSE.)
MATRIX1 = SLOW_INV(MATRIX)
CALL IEEE_GET_FLAG(IEEE_USUAL,FLAG_VALUE)
IF (FLAG_VALUE) THEN
WRITE (*, *) 'Cannot invert matrix'
STOP
END IF
END IF
CALL IEEE_SET_STATUS(STATUS_VALUE)
In this example, the function FAST_INV may cause a condition to
signal. If it does, another try is made with SLOW_INV. If this still
fails, a message is printed and the program stops. Note, also, that it
is important to set the flags quiet before the second try. The state
of all the flags is stored and restored.
Example 3:
USE, INTRINSIC :: IEEE_ARITHMETIC
LOGICAL FLAG_VALUE
:
! First try a fast algorithm for inverting a matrix.
CALL IEEE_SET_FLAG(IEEE_OVERFLOW,.FALSE.)
DO K = 1, N
:
CALL IEEE_GET_FLAG(IEEE_OVERFLOW,FLAG_VALUE)
IF (FLAG_VALUE) EXIT
END DO
IF (FLAG_VALUE) THEN
! Alternative code which knows that K-1 steps have executed normally.
:
END IF
Here the code for matrix inversion is in line and the transfer is made more
precise by adding extra tests of the flag.
Example 4:
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 set them quiet
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.