Submitter: Fred Tydeman (USA)
Submission Date: 2004-08-27
Source: WG 14
Subject: Meaning of FE_* macros in <fenv.h>
Exactly WHERE are the MEANINGS of any of the FE_* macros defined in cases where <fenv.h> applies to an environment that is not IEEE-754 (IEC 60559)?
18.104.22.168p2 Program execution says:
Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects,11) which are changes in the state of the execution environment. Evaluation of an expression may produce side effects.
11) The IEC 60559 standard for binary floating-point arithmetic requires certain user-accessible status flags and control modes. Floating-point operations implicitly set the status flags; modes affect result values of floating-point operations. Implementations that support such floating-point state are required to regard changes to it as side effects see annex F for details. The floating-point environment library <fenv.h> provides a programming facility for indicating when these side effects matter, freeing the implementations in other cases.
The above footnote is the closest I can find to a requirement that there is any relationship between floating-point operations, status flags, and modes. But, it is a footnote, and only for IEC 60559.
22.214.171.124.2p6 Characteristics of floating types <float.h> has:
The rounding mode for floating-point addition is characterized by the implementation-defined value of FLT_ROUNDS:18)-1 indeterminable 0 toward zero 1 to nearest 2 toward positive infinity 3 toward negative infinityAll other values for FLT_ROUNDS characterize implementation-defined rounding behavior.
18) Evaluation of FLT_ROUNDS correctly reflects any execution-time change of rounding mode through the function fesetround in <fenv.h>.
The above mentions, but does not define, some rounding modes.
7.6p5 Floating-point environment <fenv.h> has:
Each of the macrosFE_DIVBYZERO FE_INEXACT FE_INVALID FE_OVERFLOW FE_UNDERFLOWis defined if and only if the implementation supports the floating-point exception by means of the functions in 7.6.2. 175) Additional implementation-defined floating-point exceptions, with macro definitions beginning with FE_ and an uppercase letter, may also be specified by the implementation.
175) The implementation supports an exception if there are circumstances where a call to at least one of the functions in 7.6.2, using the macro as the appropriate argument, will succeed. It is not necessary for all the functions to succeed all the time.
The above mentions, but does not define, some floating-point exceptions.
If an implementation defines a new floating-point exception, FE_BLUEMOON, such that:
7.6p7 Floating-point environment <fenv.h> has:
Each of the macrosFE_DOWNWARD FE_TONEAREST FE_TOWARDZERO FE_UPWARDis defined if and only if the implementation supports getting and setting the represented rounding direction by means of the fegetround and fesetround functions. Additional implementation-defined rounding directions, with macro definitions beginning with FE_ and an uppercase letter, may also be specified by the implementation. The defined macros expand to integer constant expressions whose values are distinct nonnegative values.176)
176) Even though the rounding direction macros may expand to constants corresponding to the values of FLT_ROUNDS, they are not required to do so.
The above mentions, but does not define, some rounding modes.
F.8.1p1 Global transformations says:
Floating-point arithmetic operations and external function calls may entail side effects which optimization shall honor, at least where the state of the FENV_ACCESS pragma is "on". The flags and modes in the floating-point environment may be regarded as global variables; floating-point operations (+, *, etc.) implicitly read the modes and write the flags.
The above is a clear description of how modes and flags interact with operations, but it applies only to IEEE-754.
Suggested Technical Corrigendum
7.6 Floating-point environment <fenv.h>: Add to paragraph 5:
A necessary condition for an implementation to support a given FE_* exception is that it implicitly occur as a side effect of at least one floating-point operation. Just having feraiseexcept(), fetestexcept() and feclearexcept() succeed for a given FE_* exception is not sufficient.
FE_INVALID should be a side-effect of:
- operations on signaling NaN or trap representation,
- adding infinities with different signs,
- subtracting infinities with the same signs,
- multipling zero by infinity,
- dividing zero by zero and infinity by infinity,
- remainder (x REM y), where x is infinite or y is zero,
- square root of a negative number (excluding -0.0),
- converting a too large to represent floating value to an integer [both signed and unsigned], e.g., int i = INFINITY; unsigned int ui = -1.0;
- comparison with a relational operator (<, <=, >=, >) when (at least) one of the operands is a NaN.
FE_DIVBYZERO should be a side-effect of dividing a non-zero finite number by zero, e.g., 1.0/0.0. There should be no exception when dividing an infinity by zero, nor when dividing a NaN by zero.
It is implementation defined as to whether FE_INVALID, FE_DIVBYZERO, or no exception is raised for zero / zero.
FE_OVERFLOW should be a side-effect of producing a rounded floating-point result (assuming an unbounded exponent range) larger in magnitude than the largest finite number.
FE_UNDERFLOW should be a side-effect of producing a rounded floating-point result (assuming an unbounded exponent range) smaller in magnitude than the smallest non-zero finite number, or an inexact denormal number smaller than the smallest non-zero normalized number.
FE_INEXACT should be a side-effect of producing a rounded floating-point result that differs from the mathematical (or infinitely precise) result.
Also in 7.6, change footnote 175 from "The implementation supports an exception if ..." to "The implementation supports an exception if that exception happens as a side-effect of at least one floating-point operation and if ..."
126.96.36.199.2 Characteristics of floating types <float.h>: Add to paragraph 6:
See 7.6 Floating-point environment paragraph 7 for meaning of these rounding modes.
7.6 Floating-point environment <fenv.h>: Add to paragraph 7:
A necessary condition for an implementation to support these rounding control modes is that they can be set explicitly and that they affect result values of floating-point operations. Just having fegetround() and fesetround() succeed for a given FE_* rounding direction is not sufficient.
FE_TOWARDZERO means the result shall be the format's value closest to and no greater in magnitude than the infinitely precise result. For example, if rounding to integer value in floating-point format, +3.7 rounds to +3.0 and -3.7 rounds to -3.0.
FE_UPWARD means the result shall be the format's value closest to and no less than the infinitely precise result. For example, if rounding to integer value in floating-point format, +3.1 rounds to +4.0 and -3.7 rounds to -3.0.
FE_DOWNWARD means the result shall be the format's value closest to and no greater than the infinitely precise result. For example, if rounding to integer value in floating-point format, +3.7 rounds to +3.0 and -3.1 rounds to -4.0.
FE_TONEAREST means the result shall be the format's value closest to the infinitely precise result. It is implementation defined as to what happens when the two nearest representable values are equally near. For example, if rounding to integer value in floating-point format, +3.1 rounds to +3.0 and +3.7 rounds to +4.0, and +3.5 rounds to either +3.0 or +4.0.
Add to J.3.6 Floating point:
-- to nearest rounding result when the two nearest representable values are equally near.
-- whether FE_INVALID, FE_DIVBYZERO, or no exception is raised for zero / zero.
Add 7.6 to the index entry for floating-point rounding mode.
Footnote 173 in 7.6 paragraph 1 also describes intent of <fenv.h>. Footnote 180 in 188.8.131.52 paragraph 2 mentions exceptions as raised by floating-point operations.
Some members would like FE_BLUEMOON to be a valid macro (even though none of the basic floating-point operations would raise it). Hence, they do not want to require the FE_* macros to be side-effects of floating-point operations.
The current FE_* macros are unspecified as that was the best compromise that could be agreed to by the various committee members when C99 was being developed.
Not really a defect, but a deficiency.
Two Heads of Delegations would like LIA-1 added as a normative reference by C99 as a way to define floating-point in C.
Several members believe that nailing down floating-point would be a good thing, but that the DR process is not the way to do it. Perhaps an amendment (similar to how wide characters were added to C90) should be done to C99 as a way to "clean up" floating-point. Several members would like 2.0+3.0 being 5.0 to be true.
Most of the proposed TC material should be added to the C Rationale.
This material could be added to C99 as Recommended Practice.
This is not really a defect, but an area which could be addressed in a future revision of the C Standard.