[comp.lang.c] Floating point equality

Schauble@mit-multics.arpa (03/12/87)

Branner at TCGOULD.TN.CORNELL.EDU writes

In many numerical programs you do not want to repeat some calculation
if some floating-point variable has not changed.  Therefore,

          double x,y;
          x = y;
          ...
          if (x==y) ...

SHOULD be available (and work correctly) even in implementations where
(x*y == y*x) fails.  And it should be no problem to implement, since
x and y are two copies of the same number in the same internal format.
(This is very different from the common mistake of expecting infinite
precision when using FP variables in loop termination criteria...)

- Moshe Braner

2--------------------

It's rare that the two numbers are just exact copies of the same
variable. Usually one goes through slightly different calculation paths.
Also, as an extreme case, I know of one compiler where
    x=y
    if(x==y)
would fail because the x=y did rounding.

None of this mentions the countless times I've seen people using equal
to end loops, mathematical types who were surprised that sin(PI) != 1.0,
annd so on.

I'll stand by my original comment. Test for equality on floating point
numbers is machine and compiler dependant. the only question is do we
tell people about this.

For your example, you should have written 
    if (fabs(x-y) < EPSILON)

    Paul
    Schauble at MIT-Multics.edu

ger@qtecmuc.UUCP (03/16/87)

I had a similar problem today, with Microsoft C 4.0 on an IBM-AT compatible.
The two programs

#include <math.h>
double	a=0.01,
	b=0.01;
int	c;

main()
{	  
	a=floor(1.e5*a/0.5)/1.e5;
        if(a!=b)
        	printf("not equal");
        else
        	printf("equal");
}
/****/
and
/****/

/* declarations as above ... */

main()
{	  
	a=floor(1.e5*a+.5)/1.e5;
	c=1;				/* This is the only difference */
        if(a!=b)
        	printf("not equal");
        else
        	printf("equal");
}
/*****/

yielded different results. the first one says: 'Not equal',
while the other one prints out 'equal'.
With a debugger I found the reason for this strange behaviour:
The compiler tries to hold the result of the floor... statement in the
80 bit register of the 8087 or the emulator and loads just b into another 
register for the comparison, if there is no other statement inbetween. Thus 
the compiler compares the 80-bit value resulting from previous operations and 
b, which is extended from 64 bit double precision to the internal 80 bit
format, giving a!=b.
If there is another statement like 'c=1' or anything else between the
evaluation of floor .... and the comparison, the result of floor...
is written to the variable 'a' correctly  in 64 bit format, then loaded and 
extended again to 80 bit format, which results in a==b.
My question: is this behaviour legal C ????
I always thought, double variables could only be compared with double
precision, not with the precision of some internal format, depending
of other statements, like 'c=1'.
Too much optimization in my eyes.

Gerhard Pehland
Quantec Tonstudiotechnik, Munich W-Germany
UUCP: ....!mcvax!unido!qtecmuc!ger

Sorry for my english...

brianc@hpvcla.HP.COM (Brian Cripe) (03/17/87)

> For your example, you should have written 
>     if (fabs(x-y) < EPSILON)

Actually, I think the following is better:

#define FLOAT_EQUAL(a, b) (fabs((a) - (b)) < EPSILON)

if (FLOAT_EQUAL(x, y))

Brian Cripe
ihnp4!hpfcla!hpvcla!brianc

bright@dataio.Data-IO.COM (Walter Bright) (03/17/87)

In article <16800001@qtecmuc.UUCP]  ger@qtecmuc.UUCP writes:
] I had a similar problem today, with Microsoft C 4.0 on an IBM-AT compatible.
] The compiler tries to hold the result of the floor... statement in the
] 80 bit register of the 8087 and loads just b into another 
] register for the comparison, if there is no other statement inbetween. Thus 
] the compiler compares the 80-bit value resulting from previous operations and 
] b, which is extended from 64 bit double precision to the internal 80 bit
] format, giving a!=b.
] My question: is this behaviour legal C ????
] Too much optimization in my eyes.

From a purist standpoint, I agree with you, but not from a practical one.
The code would expand considerably and would slow down a lot if the
8087 registers had to be stored and reloaded after every operation. I
think it's a tradeoff that most programmers would choose, since the
reason they are generating in-line 8087 code anyway is because they
want maximum speed.