ISO/ IEC JTC1/SC22/WG14 N753

*                          Document Number:  WG14 N753/J11 97-116

                               C9X Revision Proposal

*      Title: LIA-1 Binding: Rationale
       Author: Fred J. Tydeman
       Author Affiliation: Tydeman Consulting
       Postal Address: 3711 Del Robles Dr., Austin, Texas, USA, 78727
       E-mail Address:
       Telephone Number: +1 (512) 255-8696
       Fax Number: +1 (512) 255-8696
       Sponsor: WG14
       Date: 1997-09-21
       Proposal Category:
          Y_ Editorial change/non-normative contribution
          __ Correction
          __ New feature
          __ Addition to obsolescent feature list
          __ Addition to Future Directions
          __ Other (please specify)  ______________________________
       Area of Standard Affected:
          __ Environment
          __ Language
          __ Preprocessor
          __ Library
             __ Macro/typedef/tag name
             __ Function
             __ Header
          Y_ Other (please specify)  Rational______________________
       Prior Art: C89.
       Target Audience: Programmers writing programs that perform a
       significant amount of numeric processing.___________________
       Related Documents (if any):
        WG14/N758 C9X and LIA-1 informative annex,
        WG14/N756 LIA-1 Binding: Arithmetic exception => SIGFPE,
        WG14/N755 LIA-1 Binding: <fenv.h> to <stdmath.h>,
        WG14/N752 LIA-1 Binding: Optional parts annex,
        WG14/N751 LIA-1 Binding: Combined LIA-1 + IEC-559 annex,
        WG14/N750 LIA-1 Binding: LIA-1 annex,
        WG14/N749 LIA-1 Binding: <stdlia.h>,
        WG14/N748 LIA-1 Binding: Adding 'pole' from LIA-2,
        WG14/N747 IEC 559 Binding: Signaling NaNs,
        WG14/N528 C Binding for LIA-1,
        WG14/N488 LIA-2 (math library),
        WG14/N487 LIA-1 (arithmetic),
        WG14/N486 LIA Overview,
        WG14/N463 Impact of adding LIA-1,
        WG14/N461 C Binding of LIA-1,
        NCEG 91-050 Better Environmental Inquiries for All Approximate
        NCEG 91-022 The ANSI C Language and the LCAS (Revision 1),
        NCEG 91-017 The ANSI C Language and the LCAS [LIA-1]
       Proposal Attached: _Y Yes __ No, but what's your interest?

       Abstract: This is a list of open issues (to be resolved by
       the committee) followed by the Rational for the addition of
       LIA-1 to C9X.  As issues are resolved, they will be turned
       into rational.


       Note: The '*' characters in the lefthand column are not part
       of the proposal (they are useful for emacs M-x outline mode)

       In the following, bold text, italic text,
       <TT>code sample</TT> are the conventions used to indicate
       text different from normal.

       'OPEN' in the lefthand column means the issue is still to be

*      Overview

       It appears that the minimum that an implementation needs to
       do (with respect to code generation) to support LIA is:

         Define modulo (INT_OUT_OF_BOUNDS) to be 1 (wrap) => no need
             to detect signed integer overflow.
         Detect integer divide by zero and invalid.
         Detect floating underflow, overflow, divide by zero, invalid.
         When an exception happens:
             Set indicators and proceed with a continuation value.
             Invoke a function similar to __lia_indicators() at
                 normal program termination.
             Print a "hard to ignore" message and terminate.
         Both alternatives for notification must be supported and
         the user must be able to choose which alternative to use.

       Since exceptions must be detected and acted upon, and we
       have heard complaints from some implementors that (integer)
       exception detection is hard to do, a fundamental question
       that must be answered is: In the long term, is the proposed
       Annex H normative, conditional normative or informative? In
       the short term (the committee draft of this November '97),
       it is written up as an informative annex of how C9X meets
       LIA-1.  In the long term (final committee draft of June '98
       or an amendment later), it is written up as conditional
       normative meaning if an implementor supports LIA, then it
       must be done as per that annex, but implementors are not
       required to support LIA-1.  This is the same as annex F for
       IEC 559.

OPEN   A more basic question is: Do we need LIA?  What market wants
       LIA?  Are there users requesting that implementors add
       support for LIA?  What problem does LIA solve?


OPEN   Will we allow partial conformity (Annex B in LIA-1)?  If so,
       we would allow an implementation to claim conformance, but
       they would indicate how they fall short with the following


*      Exceptions / traps / signals / interrupts

       LIA-1 requires that arithmetic exceptions be detected.
       C requires that signal handlers honor SIGFPE.
       C requires signal handlers can terminate via longjmp.

       What is not required (by C or LIA-1) is that arithmetic
       exceptions (in trap mode) map into the generation of SIGFPE
       (or any other SIG*).

OPEN   Should we require that arithmetic exceptions (that trap)
       raise SIGFPE?  Only for LIA-1 compliance?  Optional in
       non-LIA-1 mode?

       Should there be a unique SIG* for each exception?

       Once we tie arithmetic exceptions to SIGFPE (or equivalent),
       then C has a useful trap handling mechanism.

       The basic proposal is written up assuming detect, trap and
       terminate is implementation defined (no mention of SIGFPE)
       how it is done.

       The mapping of exceptions that trap get turned into SIGFPE
       is a separate proposal.


       Should we define syntax/semantics in Annex J for optional
       IEEE-754 trap functions: fesettraphandler(),
       fesavetraphandler(), ferestoretraphandler(),
       fependingtraps() or similar spelling?

       signal( SIGFPE, function ) is the equivalent of set trap
       handler.  signal( SIGFPE, SIG_IGN ) is one way to ignore
       (disable) traps. signal also can do save/restore of trap


OPEN   Do we need concept of raised exceptions as distinct from
       just set and clear? fesetexcept() and
       fesetenv() say that they do not raise exceptions, but only
       set the state of the flags. feupdateenv() says it
       saves current [raised?] exceptions ... and then raises the
       saved exceptions.

       Since we now (optionally) have the ability to enable/disable
       traps for exceptions, raised versus set matters (without
       traps, it does not matter).  A status flag starts off clear.
       An arithmetic operation fails (or feraiseexcept() is done)
       to raise the exception (what is status flag?).  If no trap
       happens (trap is disabled), then the (sticky) status flag is
       set (and a continuation value is used), else a trap happens
       (and that state of the status flag is undefined).

       Once we have raised exceptions and trap handlers, we then
       have current and pending exceptions (as seen from the trap

       It is assumed that there is a trap enable/disable control
       word.  Trap enablement is boolean: disabled, enabled.

       I do not understand the model of exceptions in the current
       C9X draft.  Some possible models are:

       1st model: one set of status flags that have three states:
         clear, raised, set.

       2nd model:  two sets of status flags:
         sticky flags are boolean: clear, set.
         exceptions are boolean: clear, raised.

       3rd model: one set of status flags that are boolean: clear,
       set.  But, now the trap enable/disable control word enters
       the picture.  Status flag set AND trap enabled means raised
       (and trap taken).  With this model, the only way for
       fesetexcept() to set a flag and not raise an exception is to
       disable the trap.


       How do we do "Hard to ignore" indicators message at

       Print to stderr is the suggested way.


OPEN   How best should sample atexit to print indicators at program
       termination be made normative?

       A suggested method is to register a function during program
       startup (as if by the use of atexit()), so that upon program
       termination, it prints out to stderr the indicators
       still set.

       During program startup, the equivalent of

         signal(SIGFPE, SIG_IGN);
         fedisabletrap( FE_TRAP_INVALID | FE_TRAP_DIVBYZERO
         iedisabletrap( INT_TRAP_INVALID | INT_TRAP_DIVBYZERO
         atexit( __lia_indicators );

       shall be executed.

       void __lia_indicators(void){ /* during program termination */
        int fp_flags = fetestexcept(FE_ALL_EXCEPT);
        int int_flags = ietestexcept(INT_ALL_EXCEPT);
        int fail = 0;
        if( (fp_flags & FE_INVALID) || (int_flags & INT_INVALID) ){
          (void)fprintf(stderr, "LIA: Undefined set");
          fail = 1;
        if( (fp_flags & FE_DIVBYZERO) || (int_flags & INT_DIVBYZERO) ){
          (void)fprintf(stderr, "LIA: Pole set");
          fail = 1;
        if( int_flags & INT_OVERFLOW ){
          (void)fprintf(stderr, "LIA: Integer overflow set");
          fail = 1;
        if( fp_flags & FE_OVERFLOW ){
          (void)fprintf(stderr, "LIA: Float overflow set");
          fail = 1;
        if( fp_flags & FE_UNDERFLOW ){
          (void)fprintf(stderr, "LIA: Float underflow set");
          fail = 1;
        if( fail ){
          exit(EXIT_FAILURE);      /* unsuccessful completion */


       What about errno?  Domain and range errors can still happen.
       C9X (independent of LIA-1) no longer requires EDOM and
       ERANGE to be assigned to errno.


OPEN   IEC 559 says: "The invalid operations are ... Conversion of
       a binary floating-point number to an integer or decimal
       format when overflow, infinity, or NaN precludes a faithful
       representation in that format and this cannot otherwise be
       signaled."  Integer overflow can be otherwise signaled, so
       it should be INT_OVERFLOW for "fp large -> int", but may be
       FE_INVALID.  Integer invalid can be otherwise signaled, so
       it should be INT_INVALID for "fp inf -> int" and "fp NaN ->
       int", but may be FE_INVALID.  Therefore, conversion from
       floating-point to integral is implementation defined via
       FP2INT_OF_LARGE.  Reason: Many existing hardware
       implementations of IEC 559 raise floating-point invalid for
       these bad conversions and an exception is raised, just not
       the one LIA-1 wants.  Counter reason: make it a slow
       function call to do what LIA-1 requires, instead of using
       the fast hardware.

       Should FP2INT_OF_* be in <stdlia.h> or <fenv.h>?  Assume


OPEN   Should fedisabletrap() return void (like feclearexcept), a
       boolean indicator (like fesetround), or the set of
       indicators that it supports? Same question for


       Should the ie*trap() and fe*trap() functions be merged into
       one set of (enable/disable/test)_trap() functions, along
       with FE_TRAP_* and INT_TRAP_* macros? For a minimal support
       of trapping (what is being proposed), there should be no
       problem having one set of functions.  But, if the standard
       or implementors were to add additional functions, similar to
       fegetexceptflag, but for traps, then the representation of
       floating-point traps might differ enough from integer traps
       to make implementation difficult or impossible.  So, they
       are separate for now.

*      Packaging

       General name space pollution.  There are many macros and
       functions that could conflict with existing user's code.  I
       am not an implementor, so do not have a vested interest in
       the names we chose, e.g., I am very willing to change the

       One way to solve pollution is to put all the new macros
       and functions into <stdlia.h> rather than in the logical place
       that they belong (<limits.h>, <float.h>, <math.h>, <stdlib.h>,
       <tgmath.h>).  That should allow existing code to
       continue to compile with a C9X compiler without change.

       A first pass at the proposal had them in the logical place
       (and that drew some complaints).

       The current proposal has them all in <stdlia.h> as name
       space pollution is a big concern with some members (do not
       break existing code just because it happens to be compiled
       with a C9X compiler).


       What is the name of the new header?  <lia.h> or <stdlia.h>?

*      Environment

OPEN   Should integer environment/flags be part of (or separate
       from) fp env./flags? I believe that the floating-point
       exception flags and the integer exception flags may have
       different status associated with the flags, hence, fexcept_t
       may not be able to hold the integer related information.  On
       the other hand, fexcept_t could have two sub-structures, one
       for integer and another for floating-point.  Same for fenv_t.

       Choices are:
         Combined arithmetic (floating-point and integer)
           environment, types, macros, and functions.  Basically,
           change 'floating-point' to 'arithmetic' in 7.6 <fenv.h>
           Could also rename header to <stdmath.h>.
         Separate floating-point and integer, minimal.
           Duplicate fe(clear/raise/test)except functions and
           change 'fe' to 'ie' and floating-point to integer.
           This is the current proposal (based upon very little
           feedback).  I believe that this is the wrong approach.
         Separate floating-point and integer, maximal.
           Duplicate almost the entire <fenv.h> into <stdlia.h>,
           and change floating-point to integer throughout.  Would
           drop rounding macros/functions.  Replace the five FE_*
           exception macros with INT_INVALID, INT_OVERFLOW, and
           INT_DIVBYZERO.  This is a lot of work for (assumed)
           very little usage.

       I believe that the best approach is to add the integer
       environment to the existing floating-point environment, call
       it the arithmetic environment and rename the header to
       <stdmath.h>. Also, change 'FENV' to 'LIAENV', 'fenv' to
       'liaenv', 'FE' to 'LIA' and 'fe' to 'lia' throughout the
       header (and rest of standard).  This allows one interface to
       the math environment, and allows existing implementations to
       continue to use their <fenv.h>, which is no longer part of
       C9X.  <stdmath.h> would replace <fenv.h> in C9X.

       We could leave the (floating-point) rounding macros and
       functions as is, since there is no extension for integer.

       If someone wants to only support IEC 559, then they can
       undefined in <stdmath.h> and it should act just like the
       existing <fenv.h>


       It is assumed that the integer and floating-point
       environments each consist of a control word and a status
       word.  The status word contains bits (sticky flags) to
       indicate the state of past operations.  The status word and
       control word need not be hardware registers, they may be in
       memory and maintained by system software.

       The floating-point environment consists of:

           sticky flags
             current operation being performed
             exception(s) of current operation
             exception(s) still pending
             operand values
             destination's precision
             rounded result

           precision (optional)
           trap enable/disable (optional)

       The integer environment consists of:

           sticky flags
             current operation being performed
             exception of current operation
             exception(s) still pending
             operand values
             destination's precision
             wrapped result

           trap enable/disable (optional)

       The integer trap enable/disable control bits also indicate
       if notification is via a trap handler (enabled) or via
       setting a flag and returning a continuation result (disabled).

*      Pragmas

       What is scope of LIA_WRAP pragma? Statement, compound
       statement, function, or translation unit?  Same as
       FENV_ACCESS pragma.


OPEN   What is the meaning of #pragma STDC LIA_NOTIFY opt before
       <stdlia.h> has been included? Must <stdlia.h> be included to give
       it meaning? Should the include be removed from the synopsis?

       I believe that all the pragmas should be independent of
       headers and should not have the include of a header in the
       synopsis section.

       Until that question is resolved, treat lack of include
       <stdlia.h> as if #pragma STDC LIA_NOTIFY UNDEF.


       Should there be a IENV_ACCESS pragma to allow the user to
       inform the implementation that the program might access the
       integer environment? I believe not, since, if the user does
       #pragma STDC LIA_NOTIFY FLAGS, they have told the
       implementation that the flags will be tested at program
       termination (at the least).


       Is there interaction between FENV_ACCESS and LIA_NOTIFY
       pragmas? Does one imply the other?  LIA_NOTIFY FLAGS |


       What happens if one translation unit contains

           #pragma STDC LIA_NOTIFY IGNORE

       and another translation unit contains

           #pragma STDC LIA_NOTIFY TRAP

       and these two translation units are part of the same

       It is implementation defined.


OPEN   What is the scope of LIA_NOTIFY pragma?  Program,
       translation unit, function, compound statement?  LIA-1 only
       requires that the entire program be translated under control
       of the same notification method (FLAGS or TRAP).  As this
       proposal is currently written, it is compound statement.


       Should it be implementation defined how IGNORE suppresses
       the final output?  It could be done at link time.

*      Boolean

OPEN   What about <stdbool.h> for booleans?

       As I understand N738 and what we did in London this past
       June, bool, true, and false are keywords if and only if
       <stdbool.h> is included.  That is, <stdbool.h> is a
       conditionaly normative header.

       If we add bool here, should it be added in the rest of the
       standard?  For example, the is* macros?

       Therefore, I believe that <stdlia.h> cannot depend upon bool,
       true, and false.  I am willing to change that belief if the
       committee directs me to.

*      Characteristics Macros

       Should rounding error be constant or track changes to
       rounding mode? I believe that it should be like FLT_ROUNDS
       (a function) and track the runtime changes.


OPEN   What value should FLT_RND_ERR have?  For C9X conformance, it
       should be the smallest value that allows most (all?) current
       implementations to conform.  For LIA-1 conformance, it must
       be 1.0.  The LIA-1 document says that Cray cannot meet 1.0,
       but does not say which machines, nor what error they can

       I have been told that for most older Cray computers, the
       errors for the operations are as follows:

	 + 1 ulp
	 - 2 ulp
	 * 2 ulp
	 / 7 ulp

       So, should there be a separate symbol for the error for each
       operation?  LIA-1 wants the same error bound and rounding
       function for all of +, -, *, and /, so one symbol works for
       LIA, but not for general C9X.  In looking at LIA-2 (which
       address the math library), they want a parameter (such as
       max_err_OP, where OP is sin, log, ...) that documents the
       maximum error for each math library operation.  In looking
       at WG14 document N756 which discusses the liagetstatus()
       function, it appears that we should have a list of symbols
       (either macros or an enum) for each floating-point operation
       and math library function and another function lia_error()
       that would take an operation/math library function name
       symbol and return the maximum error in ulps for that
       operation.  This idea has not been fleshed out (waiting to
       see were we are going with LIA).


OPEN   Should there be three *_RND_ERR macros (one for each type),
       or is one OK for all the floating point types?  Might need
       three if float and double are IEC 559 and long double is
       not, hence, long double has more error.  It would be better
       if we only had one (just like one FLT_ROUNDS).  Current
       proposal uses just one (until someone says we need three).


       The definition of modulo (INT_OUT_OF_BOUNDS) has been extended
       to include undefined to cover current C behavior: undefined
       vs wrapped vs notification.


       Should there be a distinct denotation for modulo for each
       integral type (int, long, long long)?  There is no LIA-1
       requirement that each signed integral type have its own
       (changeable) characteristics.  If we go for that additional
       control by the implementor, then the optional LIA_WRAP
       pragma needs to be extended to each integral type.  For now,
       I have removed LONG_OUT_OF_BOUNDS and LLONG_OUT_OF_BOUNDS.

*      Functions

**     Exponent and mantissa / fraction / significand

       The model representation of LIA and C9X floating-point
       numbers is: sign * p-digit fraction * base ** exponent,
       where fraction is in the range [ 1/FLT_RADIX ...  1.0 ).

       The model representation has nothing to do with the hardware

       LIA has functions to get the exponent and the fraction from
       the model representation.  LIA also has functions to get the
       integer part and the fraction part of a value.

       So, for the value 3.1416 in base 10, the representation is
        + 0.31416 * 10 ** 1.

         1.0     = exponent of model representation
         0.31416 = fraction of model representation
         3.0     = integer part of value
         0.1416  = fraction part of value

       So, the 'fraction' of x could mean the fraction of the value
       or the fraction of the model representation.  Fraction of
       the model representation has other similar names: mantissa
       or significand.  From these names, the name of the function
       could be derived.  LIA recommends 'fract' for the fraction
       of the model representation and 'frcprt' for the fraction
       part of the value.  I chose 'fracrep' and 'fracval'.  Are
       there better choices (such as mantissa)?

       For non-zero finite numbers, 1/radix <= fracrep(|x|) < 1.


       Should there be a function for exponent of the model
       representation ('exprep'), or, should it just be
       documentation that it is logb(x)+1?  Documentation.

**     Integer and fraction

       Should there be a function for integer part of value
       ('intval'), or, should it just be documentation that it can
       be obtained via modf()?  Documentation.


       Should there be a function for fraction part of value
       ('fracval'), or, should it just be documentation that it can
       be obtained via modf()?  Documentation.

**     pred and succ

       Should fpred(-INFINITY) return -INFINITY or raise invalid
       and return a NaN?  -INFINITY.

       Should fpred(0.0) raise underflow?  No.

       fpred(subnormal) does not raise underflow (unlike
       nextafter).  But, then, LIA-2 does not raise underflow for
       any math function that takes a subnormal and returns a
       subnormal, eg, sin(subnorm) is same subnorm w/o underflow.
       Their reason is underflow was already raised when the
       subnormal was created.  That reason is faulty for
       sin(DBL_TRUE_MIN) since it is an exact input value (not the
       result of previous arithmetic).  Also, the mathematical
       value of sin(subnorm) is not exactly the same subnorm, so
       the value returned is an inexact approximation of the true

       fpred and fsucc(subnorm) take an exact value and return an
       exact value.  There is no denormalization loss nor inexact,
       so underflow should not be raised.  That same statement
       should apply to nextafter (but does not, why?).


       Should fsucc(+INFINITY) return +INFINITY or raise invalid
       and return a NaN?  +INFINITY.

       Should fsucc(0.0) raise underflow?  No.

       fsucc(subnormal) does not raise underflow (unlike

**     FP -> int conversions

       Should the floating to integral conversion [*cvt()]
       operators be macros (similar to isless())? Or, is it better
       to have them be type-generic functions? Should they be in
       <stdlia.h> or <math.h>? It is easier wording-wise to put them
       in <math.h> if we want type-generic functions.  Macros.


       Should icvt(-0.0) return -0 (if it can be represented), else
       +0? The same question applies to lcvt and llcvt.  Not -0


       The casts from floating to integral cannot be used (to meet
       LIA-1 requirements) as they truncate (round toward zero) and
       LIA-1 requires round to nearest.  LIA-1 also requires, if
       modulo = wrap, that integer overflow not be raised.  The
       lround() and lrint() family of functions cannot be used as
       they may raise FE_INVALID.

       On the other hand, combining round() or rint() with a cast,
       (integer cast)round(floating), meets LIA for the round to
       nearest requirement.

       It is assumed that there is a global integer control mode to
       indicate if signed integer types are wrapping or not.  That
       control mode will affect the behavior of the *cvt()


       Should icvt(INFINITY) raise INT_INVALID or FE_INVALID? The
       same question applies to all the *cvt macros.  Since it is
       the integers that cannot represent infinity, it seems like
       it should be INT_INVALID, but some hardware does FE_INVALID.
       Implementation defined via FP2INT_OF_INF.


OPEN   FPCE: Should lround, lrint use FP2INT_OF_INF/NAN/LARGE?

**     Sign ( FP and int )

OPEN   Should *sgn() be replaced with int sgn( maxint_t i);?  That
       would replace 3 functions with 1.  Maybe.  How is maxint_t
       defined (include <inttypes.h> or redefine it here)?  In
       general, LIA-1 wants each function to return the same type
       as the type of the argument.  For the sign, where the return
       values are -1, 0, and +1, the type would not matter.  It
       could perhaps be replaced by a macro like isnan().

       Same idea: fsgn*() be replaced with float fsgn(long double);

*      Optional features

       Who determines if signed integers wrap or overflow: C9X,
       implementation, or user?

       LIA-1, in section A., says: Since modulo integers are
       dangerous, programmers should always have the option of
       using non-modulo (overflow checking) integers instead.

       The optional LIA_WRAP pragma allows the user to choose.
       INT_OUT_OF_BOUNDS is how the program can find the choice.
OPEN   Should this pragma be made normative?


       Should the addition of NANS* macros be moved from proposed
       Annex I to 7.7 <math.h> and Annex F (IEC 559)? Signaling
       NaNs are a required part of IEC 559, so to claim conformance
       to C and IEC 559, the language and the implementation need
       Signaling NaNs.  This is not a LIA-1 issue, but an IEC 559

       One standard can override another standard.  So, until
       someone has a good use of SNaNs, forget about them.

*      Deviations

       This binding of LIA-1 to C deviates from LIA-1 in the
       following ways:

       1) Signaling NaNs on IEC 559 implementations are not
       required (instead of being required).

       2) Pole is used for finite non-zero / zero (instead of
       Undefined).  DISTINGUISH_INT_DIV_BY_ZERO and
       DISTINGUISH_FP_DIV_BY_ZERO indicate if zero/zero can be
       distinguished from finite non-zero / zero.

       3) Conversion from floating-point type to integral type for
       values out-of-bounds shall raise one of INT_OVERFLOW or
       FE_INVALID (instead of just INT_OVERFLOW).  FP2INT_OF_LARGE
       indicates which one.

*      The end