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.