Complex bakeoff - example 1

Frank Farance uunet!farance.com!frank
Fri Oct 6 10:21:49 PDT 1995


> Date: 3 Oct 1995 10:40:19 -0800
> From: "Jim Thomas" <jim_thomasataligent.com>
> Subject: (SC22WG14.1732) Complex bakeoff - example 1
> To: "numeric-interest" <numeric-interestavalidgh.com>,
>         "x3j11 wg14" <sc22wg14adkuug.dk>
> 
> Infinities, NaNs, and signed zeros are key to IEEE arithmetic's completeness
> property:  operations always produce a well-defined result, which in turn
> behaves predictably in subsequent operations.  For real arithmetic, this
> property has proven useful for writing simpler more robust codes.

 I feel I occassionally need to make the following points
 about exceptional values (infinities, NaNs, signed zeroes,
 etc.) that seems to get lost when we discuss details.  These
 exceptional values aren't really values, but placeholders
 that conveniently help us write expressions that maintain
 their conceptual clarity while handling exceptional cases.
 For example, in

         T1 = R1/S1;

 the fact that finite/infinite == zero and finite/zero ==
 infinite is convenient for us *assuming we write code with
 full knowledge of how the exception handling is performed*.
 For example, the following code:

         T2 = R2/S2; /* choice 1 */
         T2 = R2/(1.0/(1.0/S2)); /* choice 2 */

 would produce the same result for varying values of S2
 (including zero and infinity).  Thus, we might believe that
 regardless of how we write the expression, the true
 ``mathematical'' result is returned.  However, this is, in
 general, not the case.  For example, if R2 and S2 are really
 the values:

         R2 = X*X;
         S2 = X;

 the true mathematical result of T2 should always be S2.
 Likewise, if R2 and S2 are the values:

         R2 = X;
         S2 = X*X;

 the true mathematical result of T2 should always be the
 reciprocal of R2.  Clearly, we can't talk about the true
 mathmematical value of T2 unless we know something about the
 nature of the expression that equates to it.  Even if the
 hardware could keep track of various types of infinities
 (e.g., infinity vs. infinity squared, infinity (the number
 of integers) vs. 2^infinity (the number of reals)) it still
 might not be able to get the correct result because the
 knowledge of the nature of R2 and S2 might be outside the
 program: the program receives its data via binary values,
 rather than attribute-loaded symbolic values (e.g., negative
 2^infinity).

 Another example is:

         T3 = (1.0/P3)*(1.0/Q3)*(1.0/R3)*(1.0/S3);

 which might produce the wrong mathematical answer if the
 compiler rewrites the expressions.  Likewise, if we rewrite
 this as:

         T3 = (1.0/P3);
         T3 *= (1.0/Q3);
         T3 *= (1.0/R3);
         T3 *= (1.0/S3);

 we can still get wrong mathematical result.  In these cases,
 I've demonstrated that you can get the wrong mathematical
 result even with unattributed infinities.  Adding in NaNs,
 signed zeroes, and signed infinities doesn't resolve the
 problems.

 As Harry Cheng pointed out, there are other ``infinity
 paradigms'' that have a single infinity in contrast to
 signed infinities.  Each paradigm is useful for a certain
 set of applications, but none are applicable 100% of the
 time (another way of saying ``yes, there are several
 branches of mathemetics'').

 So why do we care about this?  Basically, some of the
 hardware features are convenient for some of the paradigms.
 it allows us to write:

         function(param1,param2,param3)
         {
                 /*
                  * ...
                  * Lots of expressions with no
                  * testing for exceptions.
                  * ...
                  */
                 if ( isexception(result1) ||
                         isexception(result2) ||
                         isexception(result3) )
                 {
                         /*
                          * Figure out what went wrong.
                          */
                 }
         }

 When writing code that is expected to be executed in
 parallel on thousands of processors or heavily pipelined, it
 is convenient to have a linear flow control rather many
 branching cases (e.g., "if" statements, checking "errno").
 In addition to performance reasons, it is useful for program
 clarity -- imagine if every subexpression were bracketed by
 "if" statements.

 With respect to imaginaries vs. complex, there is no
 *mathmematical* need for a separate type.  When speaking
 about a pure imaginary number, e.g., 1.0I, there is no
 difference between 1.0I and 0+1.0I because the zero, in this
 case, is the value zero rather than a limiting value of zero
 (e.g., X+1.0I as X approaches zero).  Since zero is the
 identity element in addition, 1.0I is required to be
 identical to 0+1.0I.  Of course, as soon as we implement
 this on machines, there is a problem with the implementation
 because the exception handling infinity*(1.0I) is not the
 same as infinity*(0+1.0I) although they are *identical*
 mathematically.  The difference, is that a NaN is produced
 and dragged around, invalidating many subexpressions that,
 in the end, have to be discovered and re-run with the
 exception recognition code.

 The rationale for adding pure imaginaries to the type system
 is that, from a programming perspective, we desire pure
 imaginaries to behave like pure reals.  If your hardware
 doesn't have this exception handling capability for
 infinities and NaNs (e.g., some non-IEEE hardware), you have
 no choice but to write the expressions bracketed by "if"
 statements.  Thus, systems that don't support this exception
 handling have less of a need for a separate imaginary type.

 The rationale for adding imaginary types is not that it
 allows code to get mathematically correct results, but it
 facilitates performance and conceptual clarity improvements
 in the goal of getting mathematically correct results on
 hardware that supports these features.

 I am in favor of the inclusion of an imaginary type in the
 CCE proposal.

-FF
--------------------------------------------------------------------
Frank Farance, Farance Inc.   E-mail: frankafarance.com
Telephone: +1 212 486 4700    FAX: +1 212 759 1605
ISO JTC1/SC22/WG14 & ANSI X3J11 (C Programming Language) Project Editor



More information about the Numeric-interest mailing list