Date: Tue, 08 Nov 1994 11:34:16 +1100 From: Bill Metzenthen Subject: Re: 2.4/3-2.4/3!=0 To: djgpp AT sun DOT soe DOT clarkson DOT edu From: IN%"cspt AT ludens DOT elte DOT hu" "Peter Csizmadia" 8-NOV-1994 00:51:42.17 To: IN%"djgpp AT sun DOT soe DOT clarkson DOT edu" CC: Subj: RE: 2.4/3-2.4/3!=0 Date: Mon, 07 Nov 1994 11:42:24 +0100 Subject: Re: 2.4/3-2.4/3!=0 Peter Csizmadia "cspt AT ludens DOT elte DOT hu" writes: > I just received Bill Metzenthen's and Eli Zaretskii's messages. > Their explanation for the first bug is acceptable. Bill partly explained the > anomalous behaviour of the second program, but the bug is still unexplained. > I simpified the program: > > #include > main(int argc, char* argv[]) { > double a = atof(argv[1]); > double x = a/sqrt(1+a*a); > printf("1-x=%le\n", 1.0-x); > printf("x%s1\n", (x==1.0)? "==":"!="); !!! simple comparision !!! > printf("1-x=%le\n", 1.0-x); > } > > gcc g.c -o g -O1 > go32 g 10 > 1-x=4.96280979001086e-03 > x!=1 > 1-x=4.96280979001096e-03 !!! IT CHANGED !!! [stuff deleted] > So my question is: > Is it possible to compile this program with -O1 (and -ffloat-store), but > without this bug? > If it is, which optimization flag must I switch off after -O1? Ok, it wasn't clear to me that this particular point (the apparent influence of the comparison) was worrying you. I suppose that it might not be obvious, but the behaviour here is really quite simple and not due to any bug in gcc. You need to recall that a C compiler is allowed to keep stuff in registers. On an 80x86 machine, floating point registers have 64 bit precision. In the program above, the variables x and a can be kept in registers until the printf() is called. With the 80x86 version of gcc, functions assume that all floating point registers are available for local use. This means that whenever a function is called, it must be assumed that any stuff which is in floating point registers might get clobbered. In particular, in the above program the variable 'x' must be saved in some other location before the first printf() is called. gcc does this by placing 'x' in a 53 bit precision location in RAM. I hope that it is clear now that the first printf() is asked to print the results of a 64 bit precision computation (remember that the FPU is set by go32 to produce 64 bit precision results), where 'x' has been computed to 64 bit precision, while the third printf() is asked to print the results of a computation where all quantities have 53 bit precision. The comparison will of course also be dealing with a 53 bit precision value for 'x'. The bug is really with your program. It comes back to that golden rule of floating point computations - (almost) never write code which relies upon exact or "near exact" matches. There are just too many ways in which things can break, these postings have not covered all of the possibilities... There may be some way to get gcc to work around your bug, but it really would be better to re-write your code. I hope this helps. --Bill