NAG Fortran Compiler, Release 7.2: IEEE arithmetic support [4.x except as otherwise noted]

Navigation: Previous Up Next

## 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:

- separately, whether each floating point exception terminates the program or allows execution to continue (providing a default result and raising an exception flag);
- rounding mode for floating-point operations;
- underflow mode.

### 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:

- the numbers with absolute value between `TINY(X)` and `HUGE(X)` are exactly those of an IEEE floating-point format;
- the `+`, `-` and `*` operations conform to IEEE for at least one rounding mode;
- the functions `IEEE_COPY_SIGN`, `IEEE_LOGB`, `IEEE_NEXT_AFTER`, `IEEE_NEXT_DOWN`, `IEEE_NEXT_UP`, `IEEE_REM`, `IEEE_SCALB` and `IEEE_UNORDERED` may be used.

    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_AWAY`* | round to nearest (ties away from zero)
`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

* The constant `IEEE_AWAY` is a Fortran 2018 addition. The IEEE standard only requires this rounding mode for decimal, and binary hardware does not support this, so it cannot be used.

    PURE SUBROUTINE IEEE_GET_ROUNDING_MODE(ROUND_VALUE)
      TYPE(IEEE_ROUND_TYPE),INTENT(OUT) :: ROUND_VALUE

Set `ROUND_VALUE` to the current rounding mode. (Note: Fortran 2018 has added an optional `RADIX` argument to this function.)

    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`. (Note: Fortran 2018 has added an optional `RADIX` argument to this function.)

#### 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`)`≤x≤`HUGE(`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`.

Restriction: this function must not be invoked when the kind of `X` or `Y` is not an IEEE format, i.e. if `IEEE_SUPPORT_DATATYPE (X)` or `IEEE_SUPPORT_DATATYPE (Y)` returns false.

    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`

Restriction: this function must not be invoked when the kind of `X` is not an IEEE format, i.e. if `IEEE_SUPPORT_DATATYPE (X)` returns false.

    ELEMENTAL REAL(KIND(X)) 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.

Restriction: this function must not be invoked when the kind of `X` or `Y` is not an IEEE format, i.e. if `IEEE_SUPPORT_DATATYPE (X)` or `IEEE_SUPPORT_DATATYPE (Y)` returns false.

    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. (Note: Fortran 2018 has added an optional ROUND argument to this function.)

    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.