ISO/ IEC JTC1/SC22/WG14 N756

*                          Document Number:  WG14 N756/J11 97-119


                               C9X Revision Proposal
                               =====================

*      Title: LIA-1 Binding: Arithmetic exceptions => SIGFPE
       Author: Fred J. Tydeman
       Author Affiliation: Tydeman Consulting
       Postal Address: 3711 Del Robles Dr., Austin, Texas, USA, 78727
       E-mail Address: [email protected]
       Telephone Number: +1 (512) 255-8696
       Fax Number: +1 (512) 255-8696
       Sponsor: WG14
       Date: 1997-09-21
       Proposal Category:
          __ Editorial change/non-normative contribution
          __ Correction
          Y_ New feature
          __ Addition to obsolescent feature list
          __ Addition to Future Directions
          __ Other (please specify)  ______________________________
       Area of Standard Affected:
          __ Environment
          __ Language
          __ Preprocessor
          Y_ Library
             Y_ Macro/typedef/tag name
             Y_ Function
             Y_ Header
          __ Other (please specify)  ______________________________
       Prior Art: We believe that several implementations already do 
       this (for floating-point exceptions).
       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/N755 LIA-1 Binding: <fenv.h> to <stdmath.h>,
        WG14/N753 LIA-1 Binding: Rationale,
        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/N693 Type-Generic Math Functions,
        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-041 Floating-Point Modes and Status,
        NCEG 90-015 NCEG Operators,
        NCEG 89-007 Exception Handling,
        NCEG 89-005 IEEE 754 Issues
       Proposal Attached: _Y Yes __ No, but what's your interest?

       Abstract: This proposal requires that arithmetic exceptions,
       such as zero divide, get converted into raise of SIGFPE.
       This then allows user signal handlers to be trap handlers of
       arithmetic exceptions.  Such signal handlers may longjmp,
       abort, or exit.

       This does not cover return from the SIGFPE signal handler
       (replace exceptional value with value from signal handler)
       nor presubstitution (replace exceptional value with
       non-standard continuation value) as means to cope with
       exceptions.

       Proposal:

       We have four choices with this part of the proposal:

	1) Add the following text to <stdlia.h> (as normative).
	2) Add the following text to the LIA-1 annex (so that it is
	   normative if and only if the implementation supports LIA-1).
	   This is the suggested choice.
	3) Add the following text to the optional parts annex (so
	   if an implementation supports the optional feature, we
	   have standard syntax/semantics).
	4) Forget it.

       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.

*      In <stdlia.h>, 7.x.4.1.1 The LIA_NOTIFY pragma:

**     - The meaning of the UNDEF state is extended to include: In
       particular, there is no requirement that notifications
       (arithmetic exceptions) raise SIGFPE.

**     - The meaning of the TRAP state is changed to: a trap shall be
       turned into a raise of SIGFPE.

*      In LIA-1 annex, H.3.1.2 Traps:

       Change the concept of 'trap first exception and terminate is
       done via implementation defined means' to 'traps are
       converted into raise of SIGFPE'.

       There shall be a means to determine the non-numeric
       exceptional value (in LIA-1 sense) that was produced for the
       arithmetic exception.  Here is the suggested way to do that.
       (An alternative is to map each arithmetic exception into its
       own SIG* value).

****   H.3.1.2 Traps

       SIGFPE shall be sent to the executing program
       for each arithmetic exception.

       During program startup, the equivalent of

         signal(SIGFPE, SIG_DFL);
         feenabletrap( FE_TRAP_INVALID | FE_TRAP_DIVBYZERO
		| FE_TRAP_OVERFLOW | FE_TRAP_UNDERFLOW );
         ieenabletrap( INT_TRAP_INVALID | INT_TRAP_DIVBYZERO
		| INT_TRAP_OVERFLOW );

       shall be executed.

*****  H.3.1.2.1 Trap and terminate

       This shall be accomplished by using the implementation's
       default signal handler (SIG_DFL) for SIGPFE.

       The default signal handler for SIGFPE shall do the
       same as the current implementation checking of LIA-1
       indicators and "hard to ignore" message at termination.

*****  H.3.1.2.2 Trap and resume

       A user specifies code (a trap handler) to compensate for
       exceptions by:

	 signal(SIGFPE, user_trap_handler);

       where user_trap_handler is the user's trap handler.

       When SIGFPE is sent to the executing program, the user's
       signal handler for SIGFPE is invoked.

       Program execution is continued from the user's trap handler
       shall be supported by the use of the longjmp
       function.

       Return from a signal handler for SIGFPE is still undefined;
       an implementation may support return from a user's
       SIGFPE trap handler, but is not required to do so.


*      -- Add to <stdlia.h> a type, several macros and a function
       to get the details about the current arithmetic exception.

**     The type declared is

	   liastat_t

       which is a structure type that is the type of the value
       returned by the liagetstatus function.

**     The following macros, which expand to positive integral
       constant expressions with distinct values, suitable for use
       in #if preprocessing directives, some of which represent the
       non-numeric exception values returned from mathematical
       operations (see LIA-1 4.2 definitions), each corresponding
       to the specified exceptional condition:

	   LIA_XV_RAISE      raise(SIGFPE) in user's code

	   LIA_XV_INVALID    invalid or undefined operation or
			     bad argument to operation (domain)

	   LIA_XV_POLE       finite non-zero divided by zero or
			     pole of mathematical function, such as
			     log(0), or singularity

	   LIA_XV_OVERFLOW   finite result so large in magnitude
			     that it cannot be represented without
			     extraordinary roundoff error

	   LIA_XV_UNDERFLOW  finite result so small in magnitude
			     that it cannot be represented without
			     extraordinary roundoff error

	   LIA_XV_APPROX     finite result can be represented, but
			     the error between the computed result
			     and the true result exceeds the
			     allowed error for the operation.
			     Large errors may result from arguments
			     too big to the trig functions.

	   LIA_XV_INEXACT    non-zero error between computed result
			     and true result is within error bounds
			     of the operation; IEC-559 inexact by
			     itself

       are defined if and only if the implementation supports the
       exception by means of the functions in 7.x.4.2.

       LIA_XV_RAISE, LIA_XV_APPROX, and LIA_XV_INEXACT are not
       LIA-1 exception values.

       [Note: LIA_XV_APPROX is from LIA-2 where it is called
       arg_too_big.]

**     The following macros, which expand to positive integral
       constant expressions with distinct values, suitable for use
       in #if preprocessing directives, that represent the
       corresponding group of C types:

	   LIA_GRP_FLOATING   float, double, long double,
			      float complex, double complex,
			      long double complex
	   LIA_GRP_INTEGRAL   (signed, unsigned) x (char, short,
			      int, long, long long)
	   LIA_GRP_STRING     char *, wchar_t *

       are defined.

**     The following macros, which expand to positive integral
       constant expressions with distinct values, suitable for use
       in #if preprocessing directives, that represent general or
       specific mathematical operations, each corresponding to the
       specified operation:

	   LIA_OP_ZERO_DIV_ZERO // zero / zero
	   LIA_OP_INF_DIV_INF   // inf / inf
	   LIA_OP_INF_REM       // inf REM y
	   LIA_OP_REM_ZERO      // x REM zero
	   LIA_OP_INF_MOD       // inf MOD y
	   LIA_OP_MOD_ZERO      // x MOD zero
	   LIA_OP_CVT_FP_INF    // inf -> fp or int
	   LIA_OP_CVT_FP_NAN    // NaN -> fp or int
	   LIA_OP_CVT_STR_INF   // "INF" -> fp or int
	   LIA_OP_CVT_STR_NAN   // "NAN" -> fp or int
	   LIA_OP_CVT_STR_UNK   // "unknown" -> fp or int
	   LIA_OP_NANS          // signaling NaN operand
	   LIA_OP_SUBNORM       // subnormal operand
	   LIA_OP_COMP          // comparison
	   LIA_OP_ADD           // +
	   LIA_OP_SUB           // -
	   LIA_OP_MUL           // *
	   LIA_OP_DIV           // /
	   LIA_OP_SQRT          // sqrt
	   LIA_OP_LOG           // log
	   LIA_OP_EXP           // exp
				// and so on ...

       are defined if and only if the implementation supports
       exceptions by means of the functions in 7.x.4.2 for the
       specific operation and operands or general operation.
       Additional macro definitions, beginning with LIA_OP_ may
       also be specified by the implementation.

       [Note: The following details are not needed:

	 LIA_OP_INF_ADD_INF    == undefined and add    
			       == inf + (-inf) or (-inf) + inf
	 LIA_OP_INF_SUB_INF    == undefined and sub    
			       == inf - inf or (-inf) - (-inf)
	 LIA_OP_INF_MUL_ZERO   == undefined and mul    
			       == zero * inf or inf * zero
	 LIA_OP_DIV_ZERO       == pole and div         
			       == finite non-zero / zero
	 LIA_OP_LOG_ZERO       == pole and log         
			       == log(0)
	 LIA_OP_SQRT_NEG       == undefined and sqrt   
			       == sqrt(negative)
	 LIA_OP_UNORD_COMP     == undefined and comp   
			       == unordered compare

       because those operations only have one failure, which can be
       determined from the exception value and the operation]

**     7.x.4.3 The liagetstatus function

       Synopsis

	   #include <stdlia.h>
	   liastat_t liagetstatus( void );

       Description

       The liagetstatus function obtains information about the
       computational exception that caused the SIGFPE signal
       handler to be called.  liagetstatus shall be callable from a
       signal handler for SIGFPE that results from a computational
       exception.  It is implementation defined what happens when
       liagetstatus is called for signals other than SIGFPE.  It is
       implementation defined what happens when liagetstatus is
       called from other than a signal handler.

       Returns

       The liagetstatus function returns a structure of type
       liastat_t, comprising information about the current
       exception.  The structure shall contain at least the
       following members, in any order:

	      int xcp_value;   // exceptional value
	      int res_grp;     // general type of result
	   double ulp_error;   // how close is answer
	      int details;     // operation & operand

       The implementation may add more fields to give additional
       information about the exception, such as the operand
       specific types and values.

***    xcp_value shall contain either -1 (to indicate no
       information available), or one of the macros starting with
       LIA_XV_, and it indicates the non-numeric exceptional value,
       in the LIA-1 sense, returned by the arithmetic operation or
       library function that raised the exception.

***    res_grp shall contain either -1 (to indicate no information
       available), or one of the macros starting with LIA_GRP_, and
       it indicates the general type of result of the arithmetic
       operation or library function that raised the exception.

       [Note: An implementation may add a member to indicate the
       specific type with these suggest names:

	   LIA_TYP_CMPLX_LONG_DOUBLE
	   LIA_TYP_CMPLX_DOUBLE
	   LIA_TYP_CMPLX_FLOAT
	   LIA_TYP_LONG_DOUBLE
	   LIA_TYP_DOUBLE
	   LIA_TYP_FLOAT
	   LIA_TYP_EXT_INT            // signed extended integer type
	   LIA_TYP_LONG_LONG
	   LIA_TYP_LONG
	   LIA_TYP_INT
	   LIA_TYP_SHORT
	   LIA_TYP_CHAR
	   LIA_TYP_U_EXT_INT          // unsigned extended integer type
	   LIA_TYP_U_LONG_LONG
	   LIA_TYP_U_LONG
	   LIA_TYP_U_INT
	   LIA_TYP_U_SHORT
	   LIA_TYP_U_CHAR
	   LIA_TYP_STR
	   LIA_TYP_WC_STR
	   LIA_TYP_PTR
	   LIA_TYP_BOOL               // ???
       ]

***    The ulp_error field should give a rough indication of the
       error between the computed result and the true result.

	  -1.0 shall indicate this field is meaningless and includes
	       undefined, overflow, underflow.

	   0.0 shall indicate an exact answer and includes IEC 559
	       divide by zero.

	   0.5 IEC 559 inexact (by itself) in round to nearest.

	   1.0 typical non IEC 559 rnd_error for arithmetic operation.

	    +x approximate ulp error in answer from math library
	       function.

       DBL_MAX shall indicate total loss of precision or LIA-2
	       arg_to_big.

***    The details field shall contain either -1 (to indicate no
       information available), or one of the macros starting with
       LIA_OP_, and it gives a rough classification of the
       operation and operand values.  In some cases, the
       combination of xcp_value and details jointly define the
       exception (such as sqrt(negative) is LIA_XV_INVALID and
       LIA_OP_SQRT).  In other cases, the combination of xcp_value
       and res_grp jointly define the exception (such as
       FLT_MAX*FLT_MAX is LIA_XV_OVERFLOW and LIA_GRP_FLOATING).

*      -- Add the following to the combined LIA-1 + IEC 559 annex:

**     The SIGFPE signal handlers (the implementation's and the
       user's default) are the handlers for the IEC 559 exceptions.
       The signal function in <signal.h> is the means to test and
       alter the handlers.  The signal function provides the
       capability to save and restore an existing signal handler.