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_UNDERFLOWIn 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