9.6 IEEE arithmetic support [4.x except as otherwise noted]

9.6.1 Introduction

Three intrinsic modules are provided to support use of IEEE arithmetic, these are: IEEE_ARITHMETIC, IEEE_EXCEPTIONS and IEEE_FEATURES. This extension is small superset of the one described by the ISO Technical Report ISO/IEC TR 15580:1999.

9.6.2 Exception flags, modes and information flow

The model of IEEE arithmetic used by Fortran 2003 is that there is a global set of flags that indicate whether particular floating-point exceptions (such as overflow) have occurred, several operation modes which affect floating-point operations and exception handling, and a set of rules for propagating the flags and modes to obtain good performance and reliability.

The propagation rule for the exception flags is that the information “flows upwards”. Thus each procedure starts with the flags clear, and when it returns any flag that is set will cause the corresponding flag in the caller to become set. This ensures that procedures that can be executed in parallel will not interfere with each other via the IEEE exception flags. When the computer hardware only supports a single global set of flags, this model needs enforcement on in procedures that themselves examine the flags (by IEEE_GET_FLAG or IEEE_GET_STATUS).

The propagation rule for modes, is that the mode settings “flow downwards”. This enables code motion optimisations within all routines, and the only cost is that procedures which modify the modes must restore them (to the state on entry) when they return.

The modes that are available are:

9.6.3 Procedures in the modules

All the procedures provided by these modules are generic procedures, and not specific: that means that they cannot be passed as actual arguments.

The function IEEE_SELECTED_REAL_KIND, and all the functions whose names begin with IEEE_SUPPORT_, are permitted to appear in specification and constant expressions (as long as the arguments are appropriate for the context). The elemental functions are also permitted to appear in specification expressions, but not constant expressions.

In the descriptions of the procedures, where it says REAL(*) it means any kind of REAL (this is not standard Fortran syntax). Conversely, where it says LOGICAL it means default LOGICAL only, not any other kind of LOGICAL.

The functions whose names begin ‘IEEE_SUPPORT_’ are all enquiry functions. Many of these take a REAL(*) argument X; only the kind of X is used by the enquiry function, so X is permitted to be undefined, unallocated, disassociated, or an undefined pointer.

Note that a procedure must not be invoked on a data type that does not support the feature the procedure uses; the “support” enquiry functions can be used to detect this.

9.6.4 The IEEE_FEATURES module

This module defines the derived type IEEE_FEATURES_TYPE, and up to 11 constants of that type representing IEEE features: these are as follows.

IEEE_DATATYPE whether any IEEE datatypes are available
IEEE_DENORMAL whether IEEE subnormal values are available*
IEEE_DIVIDE whether division has the accuracy required by IEEE*
IEEE_HALTING whether control of halting is supported
IEEE_INEXACT_FLAG whether the inexact exception is supported*
IEEE_INF whether IEEE positive and negative infinities are available*
IEEE_INVALID_FLAG whether the invalid exception is supported*
IEEE_NAN whether IEEE NaNs are available*
IEEE_ROUNDING whether all IEEE rounding modes are available*
IEEE_SQRT whether SQRT conforms to the IEEE standard*
IEEE_UNDERFLOW_FLAG whether the underflow flag is supported*

(*) for at least one kind of REAL.

Those feature types which are required by the user procedure should be explicitly referenced by the USE statement with an ONLY clause, e.g.

  USE,INTRINSIC :: IEEE_FEATURES,ONLY:IEEE_SQRT

This ensures that if the feature specified is not available the compilation will fail.

The type IEEE_FEATURES_TYPE is not in itself useful.

9.6.5 IEEE_EXCEPTIONS

Provides data types, constants and generic procedures for handling IEEE floating-point exceptions.

9.6.5.1 Types and constants

TYPE IEEE_STATUS_TYPE
Variables of this type can hold a floating-point status value; it combines all the mode settings and flags.

TYPE IEEE_FLAG_TYPE
Values of this type specify individual IEEE exception flags; constants for these are available as follows.

IEEE_DIVIDE_BY_ZERO division by zero flag
IEEE_INEXACT inexact result flag
IEEE_INVALID invalid operation flag
IEEE_OVERFLOW overflow flag
IEEE_UNDERFLOW underflow flag

In addition, two array constants are available for indicating common combinations of flags:

  TYPE(IEEE_FLAG_TYPE),PARAMETER :: &
     IEEE_USUAL(3) = (/ IEEE_DIVIDE_BY_ZERO,IEEE_INVALID,IEEE_OVERFLOW /), &
     IEEE_ALL(5) = (/ IEEE_DIVIDE_BY_ZERO,IEEE_INVALID,IEEE_OVERFLOW, &
                      IEEE_UNDERFLOW,IEEE_INEXACT /)

9.6.5.2 Procedures

The procedures provided by IEEE_EXCEPTIONS are as follows.
ELEMENTAL SUBROUTINE IEEE_GET_FLAG(FLAG,FLAG_VALUE)
  TYPE(IEEE_FLAG_TYPE),INTENT(IN) :: FLAG
  LOGICAL,INTENT(OUT) :: FLAG_VALUE
Sets FLAG_VALUE to .TRUE. if the exception flag indicated by FLAG is currently set, and to .FALSE. otherwise.

ELEMENTAL SUBROUTINE IEEE_GET_HALTING_MODE(FLAG,HALTING)
  TYPE(IEEE_FLAG_TYPE),INTENT(IN) :: FLAG
  LOGICAL,INTENT(OUT) :: HALTING
Sets HALTING to .TRUE. if the program will be terminated on the occurrence of the floating-point exception designated by FLAG, and to .FALSE. otherwise.

PURE SUBROUTINE IEEE_GET_STATUS(STATUS_VALUE)
  TYPE(IEEE_STATUS_TYPE),INTENT(OUT) :: STATUS_VALUE
Sets STATUS_VALUE to the current floating-point status; this contains all the current exception flag and mode settings.

PURE SUBROUTINE IEEE_SET_FLAG(FLAG,FLAG_VALUE)
  TYPE(IEEE_FLAG_TYPE),INTENT(IN) :: FLAG
  LOGICAL,INTENT(IN) :: FLAG_VALUE
Sets the exception flag designated by FLAG to FLAG_VALUE. FLAG may be an array of any rank, as long as it has no duplicate values, in which case FLAG_VALUE may be scalar or an array with the same shape.

PURE SUBROUTINE IEEE_SET_HALTING_MODE(FLAG,HALTING)
  TYPE(IEEE_FLAG_TYPE),INTENT(IN) :: FLAG
  LOGICAL,INTENT(IN) :: HALTING
Sets the halting mode for the exception designated by FLAG to HALTING. FLAG may be an array of any rank, as long as it has no duplicate values, in which case HALTING may be scalar or an array with the same shape.

PURE SUBROUTINE IEEE_SET_STATUS(STATUS_VALUE)
  TYPE(IEEE_STATUS_TYPE),INTENT(IN) :: STATUS_VALUE
Sets the floating-point status to that stored in STATUS_VALUE. This must have been previously obtained by calling IEEE_GET_STATUS.

PURE LOGICAL FUNCTION IEEE_SUPPORT_FLAG(FLAG)
  TYPE(IEEE_FLAG_TYPE),INTENT(IN) :: FLAG
Returns whether the exception flag designated by FLAG is supported for all kinds of REAL.

PURE LOGICAL FUNCTION IEEE_SUPPORT_FLAG(FLAG,X)
  TYPE(IEEE_FLAG_TYPE),INTENT(IN) :: FLAG
  REAL(*),INTENT(IN) :: X
Returns whether the exception flag designated by FLAG is supported for REAL with the kind of X.

PURE LOGICAL FUNCTION IEEE_SUPPORT_HALTING(FLAG)
  TYPE(IEEE_FLAG_TYPE),INTENT(IN) :: FLAG
Returns whether control of the “halting mode” for the exception designated by FLAG is supported.

9.6.6 IEEE_ARITHMETIC module

Provides additional functions supporting IEEE arithmetic: it includes the entire contents of IEEE_EXCEPTIONS.

9.6.6.1 IEEE datatype selection

The IEEE_SELECTED_REAL_KIND function is similar to the SELECTED_REAL_KIND intrinsic function, but selects among IEEE-compliant REAL types ignoring any that are not compliant.

9.6.6.2 Enquiry functions

PURE LOGICAL FUNCTION IEEE_SUPPORT_DATATYPE()
Returns whether all real variables X satisfy the conditions for IEEE_SUPPORT_DATATYPE(X).

PURE LOGICAL FUNCTION IEEE_SUPPORT_DATATYPE(X)
  REAL(*),INTENT(IN) :: X
Returns whether variables with the kind of X satisfy the following conditions:

PURE LOGICAL FUNCTION IEEE_SUPPORT_DENORMAL()

PURE LOGICAL FUNCTION IEEE_SUPPORT_DENORMAL(X)
  REAL(*),INTENT(IN) :: X
Returns whether for all real kinds, or variables with the kind of X, subnormal values (with absolute value between zero and TINY) exist as required by IEEE and operations on them conform to IEEE.
PURE LOGICAL FUNCTION IEEE_SUPPORT_DIVIDE()

PURE LOGICAL FUNCTION IEEE_SUPPORT_DIVIDE(X)
  REAL(*),INTENT(IN) :: X
Returns whether intrinsic division (/) conforms to IEEE, for all real kinds or variables with the kind of X respectively.

PURE LOGICAL FUNCTION IEEE_SUPPORT_INF()

PURE LOGICAL FUNCTION IEEE_SUPPORT_INF(X)
  REAL(*),INTENT(IN) :: X
Returns whether for all real kinds, or variables with the kind of X, positive and negative infinity values exist and behave in conformance with IEEE.
PURE LOGICAL FUNCTION IEEE_SUPPORT_IO()

PURE LOGICAL FUNCTION IEEE_SUPPORT_IO(X)
  REAL(*),INTENT(IN) :: X
[5.2] Returns whether for all real kinds, or variables with the kind of X, conversion to and from text during formatted input/output conforms to IEEE, for the input/output rounding modes ROUND='DOWN', 'NEAREST', 'UP' and 'ZERO' (and the corresponding edit descriptors RD, RN, RU and RZ).

PURE LOGICAL FUNCTION IEEE_SUPPORT_NAN()

PURE LOGICAL FUNCTION IEEE_SUPPORT_NAN(X)
  REAL(*),INTENT(IN) :: X
Returns whether for all real kinds, or variables with the kind of X, positive and negative “Not-a-Number” values exist and behave in conformance with IEEE.
PURE LOGICAL FUNCTION IEEE_SUPPORT_ROUNDING(ROUND_VALUE)
  TYPE(IEEE_ROUND_TYPE),INTENT(IN) :: ROUND_VALUE

PURE LOGICAL FUNCTION IEEE_SUPPORT_ROUNDING(ROUND_VALUE,X)
  TYPE(IEEE_ROUND_TYPE),INTENT(IN) :: ROUND_VALUE
  REAL(*),INTENT(IN) :: X
Returns whether for all real kinds, or variables with the kind of X, the rounding mode designated by ROUND_VALUE may be set using IEEE_SET_ROUNDING_MODE and conforms to IEEE.

PURE LOGICAL FUNCTION IEEE_SUPPORT_SQRT()

PURE LOGICAL FUNCTION IEEE_SUPPORT_SQRT(X)
  REAL(*),INTENT(IN) :: X
Returns whether the intrinsic function SQRT conforms to IEEE, for all real kinds or variables with the kind of X respectively.

PURE LOGICAL FUNCTION IEEE_SUPPORT_SUBNORMAL()

PURE LOGICAL FUNCTION IEEE_SUPPORT_SUBNORMAL(X)
  REAL(*),INTENT(IN) :: X
[7.0] Returns whether for all real kinds, or variables with the kind of X, subnormal values (with absolute value between zero and TINY) exist as required by IEEE and operations on them conform to IEEE. This function is from Fortran 2018.

PURE LOGICAL FUNCTION IEEE_SUPPORT_STANDARD()

PURE LOGICAL FUNCTION IEEE_SUPPORT_STANDARD(X)
  REAL(*),INTENT(IN) :: X
Returns whether for all real kinds, or variables with the kind of X, all the facilities described by the IEEE modules except for input/output conversions (see IEEE_SUPPORT_IO) are supported and conform to IEEE.
PURE LOGICAL FUNCTION IEEE_SUPPORT_UNDERFLOW_CONTROL()

PURE LOGICAL FUNCTION IEEE_SUPPORT_UNDERFLOW_CONTROL(X)
  REAL(*),INTENT(IN) :: X
[5.2] Returns whether for all real kinds, or variables with the kind of X, the underflow mode can be controlled with IEEE_SET_UNDERFLOW_MODE.

9.6.6.3 Rounding mode

TYPE IEEE_ROUND_TYPE
Values of this type specify the IEEE rounding mode. The following predefined constants are provided.

IEEE_DOWN round down (towards minus infinity)
IEEE_NEAREST round to nearest (ties to even)
IEEE_TO_ZERO round positive numbers down, negative numbers up
IEEE_UP round up (towards positive infinity)
IEEE_OTHER any other rounding mode

PURE SUBROUTINE IEEE_GET_ROUNDING_MODE(ROUND_VALUE)
  TYPE(IEEE_ROUND_TYPE),INTENT(OUT) :: ROUND_VALUE
Set ROUND_VALUE to the current rounding mode.

PURE SUBROUTINE IEEE_SET_ROUNDING_MODE(ROUND_VALUE)
  TYPE(IEEE_ROUND_TYPE),INTENT(IN) :: ROUND_VALUE
Set the rounding mode to that designated by ROUND_VALUE.

9.6.6.4 Underflow mode

The underflow mode is either “gradual underflow” as specified by the IEEE standard, or “abrupt underflow”.

With gradual underflow, the space between -TINY(X) and TINY(X) is filled with equally-spaced “subnormal” numbers; the spacing of these numbers is equal to the spacing of model numbers above TINY(X) (and equal to the smallest subnormal number). This gradually reduces the precision of the numbers as they get closer to zero: the smallest number has only one bit of precision, so any calculation with such a number will have a very large relative error.

With abrupt underflow, the only value between -TINY(X) and TINY(X) is zero. This kind of underflow is nearly universal in non-IEEE arithmetics and is widely provided by hardware even for IEEE arithmetic. Its main advantage is that it can be much faster.

SUBROUTINE IEEE_GET_UNDERFLOW_MODE(GRADUAL)
  LOGICAL,INTENT(OUT) :: GRADUAL
Sets GRADUAL to .TRUE. if the current underflow mode is gradual underflow, and to .FALSE. if it is abrupt underflow.
SUBROUTINE IEEE_SET_UNDERFLOW_MODE(GRADUAL)
  LOGICAL,INTENT(IN) :: GRADUAL
Sets the underflow mode to gradual underflow if GRADUAL is .TRUE., and to abrupt underflow if it is .FALSE..

9.6.6.5 Number Classification

TYPE IEEE_CLASS_TYPE
Values of this type indicate the IEEE class of a number; this is equal to one of the provided constants:

IEEE_NEGATIVE_DENORMAL negative subnormal number x, in the range −TINY(x)<x<0
IEEE_NEGATIVE_INF −∞ (negative infinity)
IEEE_NEGATIVE_NORMAL negative normal number x, in the range −HUGE(x)x≤−TINY(x)
IEEE_NEGATIVE_ZERO −0 (zero with the sign bit set)
IEEE_POSITIVE_DENORMAL positive subnormal number x, in the range 0<x<TINY(x)
IEEE_POSITIVE_INF +∞ (positive infinity)
IEEE_POSITIVE_NORMAL positive normal number x, in the range TINY(x)xHUGE(x)
IEEE_POSITIVE_ZERO +0 (zero with the sign bit clear)
IEEE_QUIET_NAN Not-a-Number (usually the result of an invalid operation)
IEEE_SIGNALING_NAN Not-a-Number which raises the invalid signal on reference
[5.2] IEEE_OTHER_VALUE any value that does not fit one of the above categories

[7.0] The constants IEEE_POSITIVE_SUBNORMAL and IEEE_NEGATIVE_SUBNORMAL, from Fortran 2018, are also provided; they have the same values as IEEE_POSITIVE_DENORMAL and IEEE_NEGATIVE_DENORMAL respectively.

The comparison operators .EQ. (=) and .NE. (/=) are provided for comparing values of this type.

ELEMENTAL TYPE(IEEE_CLASS_TYPE) FUNCTION IEEE_CLASS(X)
  REAL(*),INTENT(IN) :: X
returns the classification of the value of X.

ELEMENTAL REAL(*) FUNCTION IEEE_VALUE(X,CLASS)
  REAL(*),INTENT(IN) :: X
  TYPE(IEEE_CLASS_TYPE),INTENT(IN) :: CLASS
Returns a “sample” value with the kind of X and the classification designated by CLASS.

9.6.6.6 Test functions

The following procedures are provided for testing IEEE values.

ELEMENTAL LOGICAL FUNCTION IEEE_IS_FINITE(X)
  REAL(*),INTENT(IN) :: X
Returns whether X is “finite”, i.e. not an infinity, NaN, or IEEE_OTHER_VALUE.

ELEMENTAL LOGICAL FUNCTION IEEE_IS_NAN(X)
  REAL(*),INTENT(IN) :: X
Returns whether X is a NaN.

ELEMENTAL LOGICAL FUNCTION IEEE_IS_NEGATIVE(X)
  REAL(*),INTENT(IN) :: X
Returns whether X is negative; it differs the comparison X<0 only in the case of negative zero, where it returns .TRUE..

ELEMENTAL LOGICAL FUNCTION IEEE_UNORDERED(X,Y)
  REAL(*),INTENT(IN) :: X,Y
Returns the value of ‘IEEE_IS_NAN(X) .OR. IEEE_IS_NAN(Y)’.

9.6.6.7 Arithmetic functions

ELEMENTAL REAL(*) FUNCTION IEEE_COPY_SIGN(X,Y)
  REAL(*),INTENT(IN) :: X,Y
Returns X with the sign bit of Y.

ELEMENTAL REAL(*) FUNCTION IEEE_LOGB(X)
  REAL(*),INTENT(IN) :: X
If X is zero, returns −∞ if infinity is supported and -HUGE(X) otherwise. For nonzero X, returns EXPONENT(X)-1

ELEMENTAL REAL(*) FUNCTION IEEE_NEXT_AFTER(X,Y)
  REAL(*),INTENT(IN) :: X,Y
Returns the nearest number to X that is closer to Y, or X if X and Y are equal. If the result is subnormal, IEEE_UNDERFLOW is signalled. If the result is infinite but X was finite, IEEE_OVERFLOW is signalled.

ELEMENTAL REAL(*) FUNCTION IEEE_NEXT_DOWN(X)
  REAL(*),INTENT(IN) :: X
[7.0] Returns the nearest number to X that is less than it, unless X is −∞ or NaN, in which case if X is a signalling NaN a quiet NaN is returned, otherwise X is returned. No exception is signalled unless X is a signalling NaN.

ELEMENTAL REAL(*) FUNCTION IEEE_NEXT_UP(X)
  REAL(*),INTENT(IN) :: X
[7.0] Returns the nearest number to X that is greater than it, unless X is +∞ or NaN, in which case if X is a signalling NaN a quiet NaN is returned, otherwise X is returned. No exception is signalled unless X is a signalling NaN.

ELEMENTAL REAL(*) FUNCTION IEEE_REM(X,Y)
  REAL(*),INTENT(IN) :: X,Y
Returns the exact remainder resulting from the division of X by Y.

ELEMENTAL REAL(*) FUNCTION IEEE_RINT(X)
  REAL(*),INTENT(IN) :: X
Returns X rounded to an integer according to the current rounding mode.

ELEMENTAL REAL(*) FUNCTION IEEE_SCALB(X,I)
  REAL(*),INTENT(IN) :: X
  INTEGER(*),INTENT(IN) :: I
Returns SCALE(X,I), i.e. X*2I, without computing 2I separately.