[comp.lang.c] C, roundoff anomolies, and floating comparisions

kent@xanth.UUCP (04/11/87)

In article <995@wanginst.EDU> mckeeman@wanginst.EDU (William McKeeman) writes:
>I am a bit frustrated by people talking past each other on this topic.  The
>order of evaluation rules in C are a blanket over several subproblems.
>Conclusion: when making a pitch for a better C definition rule, identify
>which of the problems:
>    unrestricted optimization
>    overflow anomalies
>    roundoff anomalies
>    side effect anomalies
>it is designed to solve.  If you don't intend for your rule to have
>language-wide implications, state the limited area of application.
>-- 
>W. M. McKeeman            mckeeman@WangInst
>Wang Institute            decvax!wanginst!mckeeman
>Tyngsboro MA 01879

I agree that this is an excellent idea, and, being nothing if not opinionated,
and having freely confessed my disenchantment with C in its present state in
this forum previously, I will start this discussion off with four new subjects
corresponding to (Mr., Mrs., Miss, Ms., Dr., (?)) McKeeman's plan, and then
sit back and read the responses.

I don't have much new to offer for the third topic, so let me just summarize
what I understand from previous postings and some (very out of date) computer
hardware experience, plus wide reading over the years.

Frequently, in order to extend the precision of floating point arithmetic,
hardware round-off, and/or guard bits are provided by the hardware designer.
The new IEEE floating point math standard is an excellent example of this.

Typically (?) the rounding takes place, or the guard bits are dropped (or
both), when the operand is returned from registers to main memory.  This can
cause a problem with relational operations between floating point variables.
A particular example is that a computational quantity which is still in a
register may fail a comparision for equality with the same datum which has
been stored in memory and returned to a register.

Previous postings have shown that the problem is not restricted to "==",
but that "<=", "<", ">=", and ">" may all suffer from variations on the same
theme, sometimes because the sum of the parts doesn't equal the whole when
round-off error is taken into account, and sometimes because of the problem
of applying rounding or dropping guard bits only when storing to memory.

One solution to the latter problem is to have the compiler, any time it
detects a relational comparision between two floating point quantities,
force any values still in registers to memory and back, so that oranges are
being compared to oranges.  This might be put under the control of a
compile time switch, for times when the performance penalty cannot be
afforded, or the comparision is know to be either exact or more than "fuzz"
different.

A solution proposed to the former problem is to provide a level of "fuzz"
in the comparision to account for "almost equal", and possibly to provide
an optimized inline way to do the fuzzy relational operations.  This seems
not yet to be well specified.

Comments?

Kent.

--
The Contradictor	Member HUP (Happily Unemployed Programmers)    // Also
								      // A
Back at ODU to learn how to program better (after 25 years!)	  \\ // Happy
								   \// Amigan!
UUCP  :  kent@xanth.UUCP   or    ...{sun,cbosgd,harvard}!xanth!kent
CSNET :  kent@odu.csnet    ARPA  :  kent@xanth.cs.odu.edu
Voice :  (804) 587-7760    USnail:  P.O. Box 1559, Norfolk, Va 23501-1559

Copyright 1987 Kent Paul Dolan.			How about if we keep the human
All Rights Reserved.  Author grants		race around long enough to see
retransmission rights recursively only.		a bit more of the universe?

dik@mcvax.UUCP (04/12/87)

In article <821@xanth.UUCP> kent@xanth.UUCP (Kent Paul Dolan) writes:
 > In article <995@wanginst.EDU> mckeeman@wanginst.EDU (William McKeeman) writes:
 > >    roundoff anomalies
 > Typically (?) the rounding takes place, or the guard bits are dropped (or
 > both), when the operand is returned from registers to main memory.  This can
 > cause a problem with relational operations between floating point variables.
 > A particular example is that a computational quantity which is still in a
 > register may fail a comparision for equality with the same datum which has
 > been stored in memory and returned to a register.
 > 
In part.  What if on your hardware A == B does not imply B == A?
(Yes this occurs, for unnormalized numbers though.)

 > One solution to the latter problem is to have the compiler, any time it
 > detects a relational comparision between two floating point quantities,
 > force any values still in registers to memory and back, so that oranges are
 > being compared to oranges.  This might be put under the control of a
 > compile time switch, for times when the performance penalty cannot be
 > afforded, or the comparision is know to be either exact or more than "fuzz"
 > different.
But, as I understand the ANSI C proposal it is possible to force storing
results in memory and using results from memory, i.e. when you use temporaries
as in:
	temp = a + b;
	if (c == temp) ...
in most languages you are not certain whether c is compared to the expression
a + b, still in registers or already stored in memory.  ANSI C provides
the volatile attribute, and when you give temp this attribute, it is stored
in the first statement and loaded again in the second (this is my understanding,
please correct me if I am totally wrong).
(It is strange to see that C in this respect outperforms numerical languages
like Fortran and Algol.  See for instance the well known algorithm to
calculate floating point machine characteristics by Malcolm (CACM,15,1972),
improved by Gentlemen & Marovitch (CACM,17,1974).  It did not work on some
machines, but would with the volatile attribute.)
(Volatile, volatile?  This number will not change!)

However, this is a kludge (just like monadic +).  What it boils down to is:
If you are using floating point, know what you are doing, and know your
compiler.  If you want to do it portable, use defensive programming,
i.e. assume nothing.  (Do you assume 3.0 / 3.0 == 1.0?  It is not true!
Or A * 2.0 / 2.0 == A (assuming no overflow occurs).  This is not true either!)
-- 
dik t. winter, cwi, amsterdam, nederland
INTERNET   : dik@cwi.nl
BITNET/EARN: dik@mcvax