[comp.lang.c] == comparison of two doubles on an 80386 not right?

flint@gistdev.gist.com (Flint Pellett) (03/28/91)

I came across something today which has me quite baffled: some old
code I found was trying to test equality of two successive long
values by testing for equality of a union'ed double on top of them.
Such a thing obviously isn't portable, (and I fixed it to use integer
comparisons) but what has me confused is what it _was_ doing: it works
differently on a 3B2 from the way it works on a 386 (both SYSV UNIX).
If the endian-ness difference is the explanation, I don't see how.
Here is a test program with output from the 3B2 and the 386:

--------- CUT HERE ------------
typedef union {
	double	f;
	struct {
		long l1;
		long l2;
	} l;
} BOTH;

main()
{
	BOTH var1, var2;
	/* Construct two significantly different 64 bit bitmaps, then
	** try to compare them by comparing the floating point values. */
	var1.l.l1 = var2.l.l1 = 0L;

	/* any value of l.l2 from 64 to 127 produces "They match" on a 386,
	** but values of .l2 from <63 or >128 produce "They do NOT match".
	** On the 3B2 it doesn't match unless var1.l.l2 == var2.l.l2 */
	var1.l.l2 = 127L;
	var2.l.l2 = 100L;

	if (var1.f == var2.f)
		(void)printf("They match %lg %lg\n",var1.f,var2.f);
	else
		(void)printf("They do NOT match %lg %lg\n",var1.f,var2.f);
}

--------- CUT HERE ------------
386 output is: They match 2.69493e-312 2.122e-312
3B2 output is: They do NOT match 6.27463e-322 4.94066e-322

Can anyone explain this?  That the 386 would tell me the two values
are equal and then display different values has me totally perplexed.
I suppose the answer is obvious and I'll feel like a fool for posting
this, but I sure don't see it.  (I know why the values the 3B2
has aren't the same as on the 386: the question is how come the
386 thinks 2.69 == 2.12.)
-- 
Flint Pellett, Global Information Systems Technology, Inc.
1800 Woodfield Drive, Savoy, IL  61874     (217) 352-1165
uunet!gistdev!flint or flint@gistdev.gist.com

steve@taumet.com (Stephen Clamage) (03/29/91)

flint@gistdev.gist.com (Flint Pellett) writes:

>I came across something today which has me quite baffled: some old
>code I found was trying to test equality of two successive long
>values by testing for equality of a union'ed double on top of them.
>Such a thing obviously isn't portable, (and I fixed it to use integer
>comparisons) but what has me confused is what it _was_ doing: it works
>differently on a 3B2 from the way it works on a 386 (both SYSV UNIX).
>If the endian-ness difference is the explanation, I don't see how.

Floating-point formats often reserve several bit patterns for special
purposes.  Some of these patterns are distinguished only by the most
significant bits.  If two numbers are the same in these bits (which
could be at either end of a number, depending on the endian-ness),
they could compare equal even though other bits differ.  Similarly,
some bit patterns could cause an exception, and some will always
compare unequal even if the bit patterns are identical.

As you noted, the code was not at all portable, and may not have
worked properly even on the machine where it was originally written.
It's not nice to fool the compiler.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com