ISO Technical Reports TR 15580 and TR 15581IEEE Floating-point Modules and Allocatable Attribute

IEEE Floating-point Modules and Allocatable Attribute

Overview

TR 15580 specifies three intrinsic modules that provide access to IEEE floating-point features, and additional syntax on the USE statement to specify whether an intrinsic or non-instrinsic (i.e. user-defined) module is required.

TR 15581 allows the use of the ALLOCATABLE attribute on:

  • dummy arguments
  • function results
  • structure components

TR 15580: IEEE arithmetic

USE statement changes

The ",INTRINSIC" or ",NON_INTRINSIC" specifiers may be used to specify whether an intrinsic or non-intrinsic module is required. If these are not used, the compiler will pick an intrinsic module only if no user-defined module is found. For example:

  USE,INTRINSIC :: ieee_exceptions

Note that the double-colon "::" is required if either specifier is used.

IEEE_FEATURES module

Defines a derived type, IEEE_FEATURES_TYPE, and up to 11 constants of that type representing IEEE features: these are

IEEE_DATATYPE
- whether any IEEE datatypes are available,
IEEE_DENORMAL
- whether IEEE denormal 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 underflow is supported (*).
(*) for at least one kind of REAL.

Only those feature types which are required by the user procedure should be referenced, i.e. the ONLY clause should be used, e.g.

  USE,INTRINSIC :: IEEE_FEATURES,ONLY:IEEE_SQRT

If the feature specified is not available the compilation will fail.

The type IEEE_FEATURES_TYPE is not in itself useful.

IEEE_EXCEPTIONS module

Provides data types, constants and generic procedures for IEEE exceptions.

TYPE IEEE_STATUS_TYPE

Variables of this type can hold a floating-point status value.

SUBROUTINE IEEE_GET_STATUS(STATUS_VALUE)
TYPE(IEEE_STATUS_TYPE),INTENT(OUT) :: STATUS_VALUE

Stores the current floating-point status into the STATUS_VALUE argument.

SUBROUTINE IEEE_SET_STATUS(STATUS_VALUE)
TYPE(IEEE_STATUS_TYPE),INTENT(IN) :: STATUS_VALUE

Sets the current floating-point status from the STATUS_VALUE argument.

TYPE IEEE_FLAG_TYPE

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

TYPE(IEEE_FLAG_TYPE),PARAMETER :: IEEE_DIVIDE_BY_ZERO
TYPE(IEEE_FLAG_TYPE),PARAMETER :: IEEE_INEXACT
TYPE(IEEE_FLAG_TYPE),PARAMETER :: IEEE_INVALID
TYPE(IEEE_FLAG_TYPE),PARAMETER :: IEEE_OVERFLOW
TYPE(IEEE_FLAG_TYPE),PARAMETER :: IEEE_UNDERFLOW

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_OVERFLOW,IEEE_DIVIDE_BY_ZERO, &
                         IEEE_INVALID,IEEE_UNDERFLOW,IEEE_INEXACT /)
LOGICAL FUNCTION IEEE_SUPPORT_FLAG(FLAG,X)
TYPE(IEEE_FLAG_TYPE),INTENT(IN) :: FLAG
REAL(kind),INTENT(IN),OPTIONAL :: X

Returns TRUE if detection of the specified IEEE exception is supported for the REAL kind of X (if X is present), or for all REAL kinds (if X is absent).

LOGICAL FUNCTION IEEE_SUPPORT_HALTING(FLAG)
TYPE(IEEE_FLAG_TYPE),INTENT(IN) :: FLAG

Returns TRUE if IEEE_SET_HALTING_MODE can be used to change whether the processor terminates the program on receiving the specified exception.

ELEMENTAL SUBROUTINE IEEE_GET_FLAG(FLAG,FLAG_VALUE)
TYPE(IEEE_FLAG_TYPE),INTENT(IN) :: FLAG
LOGICAL,INTENT(OUT) :: FLAG_VALUE

Sets (each element of) FLAG_VALUE to TRUE if the corresponding exception specified by FLAG is signalling, and to FALSE otherwise.

ELEMENTAL SUBROUTINE IEEE_GET_HALTING_MODE(FLAG,HALTING)
TYPE(IEEE_FLAG_TYPE),INTENT(IN) :: FLAG
LOGICAL,INTENT(OUT) :: HALTING

Sets (each element of) HALTING to TRUE if the corresponding exception specified by FLAG is signalling, and to FALSE otherwise.

ELEMENTAL SUBROUTINE IEEE_SET_FLAG(FLAG,FLAG_VALUE)
TYPE(IEEE_FLAG_TYPE),INTENT(OUT) :: FLAG
LOGICAL,INTENT(IN) :: FLAG_VALUE

Sets the exception flag specified by (each element of) FLAG to signalling or quiet according to the corresponding element of FLAG_VALUE.

ELEMENTAL SUBROUTINE IEEE_SET_HALTING_MODE(FLAG,HALTING)
TYPE(IEEE_FLAG_TYPE),INTENT(OUT) :: FLAG
LOGICAL,INTENT(IN) :: HALTING

Sets the halting mode for each exception specified by FLAG to the value of the corresponding element of HALTING (TRUE = halt).

IEEE_ARITHMETIC module

IEEE\_ARITHMETIC is an intrinsic module providing IEEE arithmetic facilities. The contents of this module conform to technical report ISO/IEC TR15580:1998(E).

1. IEEE datatype selection

INTEGER FUNCTION SELECTED_REAL_KIND(P,R)
INTEGER(kind1),OPTIONAL :: P
INTEGER(kind2),OPTIONAL :: R

The same as the SELECTED_REAL_KIND intrinsic, but only returns numbers of of IEEE kinds of reals.

2. General support enquiry functions

LOGICAL FUNCTION IEEE_SUPPORT_DATATYPE(X)
REAL(kind),OPTIONAL :: X

Whether IEEE arithmetic is supported for the same kind of REAL as X (or for all REAL kinds if X is absent).

LOGICAL FUNCTION IEEE_SUPPORT_DENORMAL(X)
REAL(kind),OPTIONAL :: X

Whether IEEE denormal values are supported for the same kind of REAL as X (or for all REAL kinds if X is absent).

LOGICAL FUNCTION IEEE_SUPPORT_DIVIDE(X)
REAL(kind),OPTIONAL :: X

Whether division is carried out to the accuracy specified by the IEEE standard for the same kind of REAL as X (or for all REAL kinds if X is absent).

LOGICAL FUNCTION IEEE_SUPPORT_INF(X)
REAL(kind),OPTIONAL :: X

Whether IEEE infinite values are supported for the same kind of REAL as X (or for all REAL kinds if X is absent).

LOGICAL FUNCTION IEEE_SUPPORT_NAN(X)
REAL(kind),OPTIONAL :: X

Whether IEEE NaN (Not-a-Number) values are supported for the same kind of REAL as X (or for all REAL kinds if X is absent).

LOGICAL FUNCTION IEEE_SUPPORT_SQRT(X)
REAL(kind),OPTIONAL :: X

Whether SQRT conforms to the IEEE standard for the same kind of REAL as X (or for all REAL kinds if X is absent).

LOGICAL FUNCTION IEEE_SUPPORT_STANDARD(X)
REAL(kind),OPTIONAL :: X

Whether all the IEEE facilities specified by the TR are supported for the same kind of REAL as X (or for all REAL kinds if X is absent).

3. Rounding Modes

TYPE IEEE_ROUND_TYPE

Values of this type specify the IEEE rounding mode.

TYPE(IEEE_ROUND_TYPE),PARAMETER :: IEEE_DOWN
TYPE(IEEE_ROUND_TYPE),PARAMETER :: IEEE_NEAREST
TYPE(IEEE_ROUND_TYPE),PARAMETER :: IEEE_TO_ZERO
TYPE(IEEE_ROUND_TYPE),PARAMETER :: IEEE_UP
LOGICAL FUNCTION IEEE_SUPPORT_ROUNDING(ROUND_VALUE,X)
TYPE(IEEE_ROUND_TYPE),INTENT(IN) :: ROUND_VALUE
REAL(kind),OPTIONAL :: X

Whether the specified IEEE rounding mode is supported for the same kind of REAL as X (or for all REAL kinds if X is absent).

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

Sets the ROUND_VALUE argument to the current IEEE rounding mode.

SUBROUTINE IEEE_SET_ROUNDING_MODE(ROUND_VALUE)
TYPE(IEEE_ROUND_TYPE),INTENT(IN) :: ROUND_VALUE

Sets the current IEEE rounding mode to that specified by ROUND_VALUE.

4. Number Classification

TYPE IEEE_CLASS_TYPE

Values of this type indicate the IEEE class of a number.

TYPE(IEEE_CLASS_TYPE),PARAMETER :: IEEE_NEGATIVE_DENORMAL
TYPE(IEEE_CLASS_TYPE),PARAMETER :: IEEE_NEGATIVE_INF
TYPE(IEEE_CLASS_TYPE),PARAMETER :: IEEE_NEGATIVE_NORMAL
TYPE(IEEE_CLASS_TYPE),PARAMETER :: IEEE_NEGATIVE_ZERO
TYPE(IEEE_CLASS_TYPE),PARAMETER :: IEEE_POSITIVE_DENORMAL
TYPE(IEEE_CLASS_TYPE),PARAMETER :: IEEE_POSITIVE_INF
TYPE(IEEE_CLASS_TYPE),PARAMETER :: IEEE_POSITIVE_NORMAL
TYPE(IEEE_CLASS_TYPE),PARAMETER :: IEEE_POSITIVE_ZERO
TYPE(IEEE_CLASS_TYPE),PARAMETER :: IEEE_QUIET_NAN
TYPE(IEEE_CLASS_TYPE),PARAMETER :: IEEE_SIGNALING_NAN
ELEMENTAL TYPE(IEEE_CLASS_TYPE) FUNCTION IEEE_CLASS(X)
REAL(kind),INTENT(IN) :: X

Returns the appropriate value of IEEE_CLASS_TYPE for the number X, which may be of any IEEE kind.

In addition to ISO/IEC TR 15580:1998(E), the module IEEE_ARITHMETIC defines the "==" and "/=" operators for the IEEE_CLASS_TYPE. These may be used to test the return value of the IEEE_CLASS function. E.g

  USE,INTRINSIC :: IEEE_ARITHMETIC, ONLY: IEEE_CLASS, &
    IEEE_QUIET_NAN, OPERATOR(==)
  ...
  IF (IEEE_CLASS(X)==IEEE_QUIET_NAN) THEN
  ...

ELEMENTAL REAL(kind) FUNCTION IEEE_VALUE(X,CLASS)
REAL(kind),INTENT(IN) :: X
TYPE(IEEE_CLASS_TYPE),INTENT(IN) :: CLASS

Returns a sample value of the specified class for the same kind of real as X, which may be of any IEEE kind.

ELEMENTAL LOGICAL FUNCTION IEEE_IS_FINITE(X)
REAL(kind),INTENT(IN) :: X

Returns TRUE if X is not infinite or NaN.

ELEMENTAL LOGICAL FUNCTION IEEE_IS_NAN(X)
REAL(kind),INTENT(IN) :: X

Returns TRUE if X is either a signaling or quiet NaN.

ELEMENTAL LOGICAL FUNCTION IEEE_IS_NEGATIVE(X)
REAL(kind),INTENT(IN) :: X

Returns TRUE if X is negative, including negative zero.

ELEMENTAL LOGICAL FUNCTION IEEE_IS_NORMAL(X)
REAL(kind),INTENT(IN) :: X

Returns TRUE if X is not an infinity, NaN, or denormal.

ELEMENTAL LOGICAL FUNCTION IEEE_UNORDERED(X,Y)
REAL(kind),INTENT(IN) :: X,Y

Returns TRUE if X is a NaN or if Y is a NaN.

5. Arithmetic operations

ELEMENTAL REAL(kind) FUNCTION IEEE_COPY_SIGN(X,Y)
REAL(kind),INTENT(IN) :: X,Y

Returns X with the sign of Y, even for NaNs and infinities.

ELEMENTAL REAL(kind) FUNCTION IEEE_LOGB(X)
REAL(kind),INTENT(IN) :: X

Returns the unbiased exponent as a REAL value;
if X is zero, IEEE_DIVIDE_BY_ZERO signals and the result is -infinity if IEEE infinities are supported for that kind, and -HUGE(X) if not;


if X is infinite, the result is +infinity;
if X is a NaN, the result is a quiet NaN (the same one if X is a quiet NaN); otherwise the result is EXPONENT(X)-1.
ELEMENTAL REAL(kind) FUNCTION IEEE_NEXT_AFTER(X,Y)
REAL(kind),INTENT(IN) :: X,Y
The same as NEAREST(X,1.0_kind) for Y>X and NEAREST(X,-1.0_kind) for Y<X; if Y==X, the result is X, if either X or Y are NaNs the result is one of these NaNs.
ELEMENTAL REAL(kind) FUNCTION IEEE_REM(X,Y)
REAL(kind),INTENT(IN) :: X,Y

X-Y*N exactly, where N is the integer nearest to the exact value X/Y. If the result is zero, it has the same sign as X. This function is not affected by the rounding mode.

ELEMENTAL REAL(kind) FUNCTION IEEE_RINT(X)
REAL(kind),INTENT(IN) :: X

Round to an integer according to the current rounding mode.

ELEMENTAL REAL(kind) FUNCTION IEEE_SCALB(X,I)
REAL(kind1),INTENT(IN) :: X
INTEGER(kind2),INTENT(IN) :: I

The same as SCALE(X,I).

Allocatable Dummy Arrays

A dummy argument can be declared to be an allocatable array, e.g.

    SUBROUTINE S(DUM)
      REAL,ALLOCATABLE :: DUM(:,:)
      ...
    END SUBROUTINE

Having an allocatable dummy argument means that there must be an explicit interface for any reference: i.e. if the procedure is not an internal or module procedure there must be an accessible interface block in any routine which references that procedure.

Any actual argument that is passed to an allocatable dummy array must itself be an allocatable array; it must also have the same type, kind type parameters, and rank. For example:

   REAL,ALLOCATABLE :: X(:,:)
   CALL S(X)

The actual argument need not be allocated before calling the procedure, which may itself allocate or deallocate the argument. For example:

   PROGRAM example2
     REAL,ALLOCATABLE :: x(:,:)
     OPEN(88,FILE='myfile',FORM='unformatted')
     CALL read_matrix(x,88)
     !
     ... process x in some way
     !
     REWIND(88)
     CALL write_and_delete_matrix(x,88)
   END
   !
   MODULE module
   CONTAINS
     !
     ! This procedure reads the size and contents of an array from an
     ! unformatted unit.
     !
     SUBROUTINE read_matrix(variable,unit)
       REAL,ALLOCATABLE,INTENT(OUT) :: variable(:,:)
       INTEGER,INTENT(IN) :: unit
       INTEGER dim1,dim2
       READ(unit) dim1,dim2
       ALLOCATE(variable(dim1,dim2))
       READ(unit) variable
       CLOSE(unit)
     END SUBROUTINE
     !
     ! This procedures writes the size and contents of an array to an
     ! unformatted unit, and then deallocates the array.
     !
     SUBROUTINE write_and_delete_matrix(variable,unit)
       REAL,ALLOCATABLE,INTENT(INOUT) :: variable(:,:)
       INTEGER,INTENT(IN) :: unit
       WRITE(unit) SIZE(variable,1),SIZE(variable,2)
       WRITE(unit) variable
       DEALLOCATE(variable)
     END SUBROUTINE
   END

Allocatable Function Results

The result of a function can be declared to be an allocatable array, e.g.

    FUNCTION af() RESULT(res)
      REAL,ALLOCATABLE :: res

On invoking the function, the result variable will be unallocated. It must be allocated before returning from the function. For example:

    !
    ! The result of this function is the original argument with adjacent
    ! duplicate entries deleted (so if it was sorted, each element is unique).
    !
    FUNCTION compress(array)
      INTEGER,ALLOCATABLE :: compress(:)
      INTEGER,INTENT(IN) :: array(:)
      IF (SIZE(array,1)==0) THEN
        ALLOCATE(compress(0))
      ELSE
        N = 1
        DO I=2,SIZE(array,1)
          IF (array(I)/=array(I-1)) N = N + 1
        END DO
        ALLOCATE(compress(N))
        N = 1
        compress(1) = array(1)
        DO I=2,SIZE(array,1)
          IF (array(I)/=compress(N)) THEN
            N = N + 1
            compress(N) = array(I)
          END IF
        END DO
      END IF
    END

The result of an allocatable array function is automatically deallocated after it has been used.

Allocatable Structure Components

A structure component can be declared to be allocatable, e.g.

  MODULE matrix_example
    TYPE MATRIX
      REAL,ALLOCATABLE :: value(:,:)
    END TYPE
  END MODULE

An allocatable array component is initially not allocated, just like allocatable array variables. On exit from a procedure containing variables with allocatable components, all the allocatable components are automatically deallocated. This is in contradistinction to pointer components, which are not automatically deallocated. For example:

  SUBROUTINE sub(n,m)
    USE matrix_example
    TYPE(matrix) a,b,c
    !
    ! a%value, b%value and c%value are all unallocated at this point.
    !
    ALLOCATE(a%value(n,m),b%value(n,m))
    !
    ... do some computations, then
    !
    RETURN
    !
    ! Returning from the procedure automatically deallocates a%value, b%value,
    ! and c%value (if they are allocated).
    !
  END

Deallocating a variable that has an allocatable array component deallocates the component first; this happens recursively so that all ALLOCATABLE subobjects are deallocated with no memory leaks.

Any allocated allocatable components of a function result are automatically deallocated after the result has been used.

  PROGRAM deallocation_example
    TYPE inner
      REAL,ALLOCATABLE :: ival(:)
    END TYPE
    TYPE outer
      TYPE(inner),ALLOCATABLE :: ovalue
    END TYPE
    TYPE(outer) x
    !
    ! At this point, x%ovalue is unallocated
    !
    ALLOCATE(x%ovalue(10))
    !
    ! At this point, x%ovalue(i)%ival are unallocated, i=1,10
    !
    ALLOCATE(x%ovalue(2)%ival(1000),x%ovalue(5)%ival(9999))
    !
    ! Only x%ovalue(2)%ival and x%ovalue(5)%ival are allocated
    !
    DEALLOCATE(x%ovalue)
    !
    ! This has automatically deallocated x%ovalue(2)%ival and x%ovalue(5)%ival
    !
  END

In a structure constructor for such a type, the expression corresponding to an allocatable array component can be

  • the NULL() intrinsic, indicating an unallocated array,
  • an allocatable array which may be allocated or unallocated, or
  • any other array expression, indicating an allocated array.
  SUBROUTINE constructor_example
    USE matrix_example
    TYPE(matrix) a,b,c
    REAL :: array(10,10) = 1
    REAL,ALLOCATABLE :: alloc_array(:,:)
    a = matrix(NULL())
    !
    ! At this point, a%value is unallocated
    !
    b = matrix(array*2)
    !
    ! Now, b%value is a (10,10) array with each element equal to 2.
    !
    c = matrix(alloc_array)
    !
    ! Now, c%value is unallocated (because alloc_array was unallocated).
    !
  END

Intrinsic assignment of such types does a "deep copy" of the allocatable array components; it is as if the allocatable array component were deallocated (if necessary), then if the component in the expression was allocated, the variable's component is allocated to the right size and the value copied.

  SUBROUTINE assignment_example
    USE matrix_example
    TYPE(matrix) a,b
    !
    ! First we establish a value for a
    !
    ALLOCATE(a%value(10,20))
    a%value(3,:) = 30
    !
    ! And a value for b
    !
    ALLOCATE(b%value(1,1))
    b%value = 0
    !
    ! Now the assignment
    !
    b = a
    !
    ! The old contents of b%value have been deallocated, and b%value now has
    ! the same size and contents as a%value.
    !
  END

Allocatable Component Example

This example shows the definition and use of a simple module that provides polynomial arithmetic. To do this it makes use of intrinsic assignment for allocatable components, the automatically provided structure constructors and defines the addition (+) operator. A more complete version of this module would provide other operators such as multiplication.

!
! Module providing a single-precision polynomial arithmetic facility
!
MODULE real_poly_module
  !
  ! Define the polynomial type with its constructor.
  ! We will use the convention of storing the coefficients in the normal
  ! order of highest degree first, thus in an N-degree polynomial, COEFF(1)
  ! is the coefficient of X**N, COEFF(N) is the coefficient of X**1, and
  ! COEFF(N+1) is the scalar.
  !
  TYPE,PUBLIC :: real_poly
    REAL,ALLOCATABLE :: coeff(:)
  END TYPE
  !
  PUBLIC OPERATOR(+)
  INTERFACE OPERATOR(+)
    MODULE PROCEDURE rp_add_rp,rp_add_r,r_add_rp
  END INTERFACE
  !
CONTAINS
  TYPE(real_poly) FUNCTION rp_add_r(poly,real)
    TYPE(real_poly),INTENT(IN) :: poly
    REAL,INTENT(IN) :: real
    INTEGER isize
    IF (.NOT.ALLOCATED(poly%coeff)) STOP 'Undefined polynomial value in +'
    isize = SIZE(poly%coeff,1)
    rp_add_r%coeff(isize) = poly%coeff(isize) + real
  END FUNCTION
  TYPE(real_poly) FUNCTION r_add_rp(real,poly)
    TYPE(real_poly),INTENT(IN) :: poly
    REAL,INTENT(IN) :: real
    r_add_rp = rp_add_r(poly,real)
  END FUNCTION
  TYPE(real_poly) FUNCTION rp_add_rp(poly1,poly2)
    TYPE(real_poly),INTENT(IN) :: poly1,poly2
    INTEGER I,N,N1,N2
    IF (.NOT.ALLOCATED(poly1%coeff).OR..NOT.ALLOCATED(poly2%coeff)) &
      STOP 'Undefined polynomial value in +'
    ! Set N1 and N2 to the degrees of the input polynomials
    N1 = SIZE(poly1%coeff) - 1
    N2 = SIZE(poly2%coeff) - 1
    ! The result polynomial is of degree N
    N = MAX(N1,N2)
    ALLOCATE(rp_add_rp%coeff(N+1))
    DO I=0,MIN(N1,N2)
      rp_add_rp%coeff(N-I+1) = poly1%coeff(N1-I+1) + poly2%coeff(N2-I+1)
    END DO
    ! At most one of the next two DO loops is ever executed
    DO I=N1+1,N
      rp_add_rp%coeff(N-I+1) = poly2%coeff(N2-I+1)
    END DO
    DO I=N2+1,N
      rp_add_rp%coeff(N-I+1) = poly1%coeff(N1-I+1)
    END DO
  END FUNCTION
END MODULE
!
! Sample program
!
PROGRAM example
  USE real_poly_module
  TYPE(real_poly) p,q,r
  p = real_poly((/1.0,2.0,4.0/))   ! x**2 + 2x + 4
  q = real_poly((/1.0,-5.5/))      ! x - 5.5
  r = p + q                        ! x**2 + 3x - 1.5
  print 1,'The coefficients of the answer are:',r%coeff
1 format(1x,A,3F8.2)
END

When executed, the above program prints:

 The coefficients of the answer are:    1.00    3.00   -1.50

Website Feedback

If you would like a response from NAG please provide your e-mail address below.

(If you're a human, don't change the following field)
Your first name.
CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.