Path: utzoo!utgpu!attcan!uunet!mstan!amull From: amull@Morgan.COM (Andrew P. Mullhaupt) Newsgroups: comp.lang.c Subject: Re: Bug? Summary: Comparison with Tolerance; Avoid like Plague Message-ID: <412@s5.Morgan.COM> Date: 30 Sep 89 16:16:28 GMT References: <19831@mimsy.UUCP> <15852@dartvax.Dartmouth.EDU> <364@capmkt.COM> <1989Sep29.144716.20921@brutus.cs.uiuc.edu> Organization: Morgan Stanley & Co. NY, NY Lines: 58 When comparing floating point numbers for equality, you are in grave peril of several incredibly painful bugs, to wit: 1. Forget portability across machines. 2. The 'storage history' fun: If your computer has a coprocessor or FPA, you may find that IEEE arithmetic (80 bits wide) is done there, but your number comes back to the CPU as a double. This means that z = functionreturningdouble(); if ( y == z ) printf("Spew"); and if ( y == functionreturningdouble() ) printf("Spew"); need not have the same output. The classic example of this torture is a bug where an expression needs to be debugged is computed in the coprocessor (80 bit) registers, If the compiler has arrived at this situation through optimization, and the program is not correct with the extra bits of precision, then turning off optimization, (which almost always happens if you compile for debugging), will make the bug go away! If you observe this behavior, and decide to resort to the insertion of diagnostic print statements, (because you realize that you can't debug the program with the debugger), then the number which gets printed out (i.e. has been coerced to double as it crossed the CPU to be output), will appear to be correct, and the print statement may actually fix the bug! It is possible that in versions of C which have peculiar single and double automatic conversions that this kind of bug occurs as well. 3. If I have a teeny tiny double called epsilon can I make this all go away? Mostly yes, but strictly speaking, NO!!!!! If either you, or your compiler (in a misguided imitation of APL's comparison tol- erance) insert efficiency sapping +epsilon and -epsilon all over your code, it displaces the problem to the comparisons y - epsilon < z and y + epsilon > z either of which can suffer from the storage history disease if the difference involved is between two relevant precisions. In fact, you may be inviting trouble by giving the compiler more to rearrange in optimization. The moral of the story is: Unless you are dead certain that nothing else will do, comparing floating point numbers for equality is a bad business, and your compiler ought not pretend to solve this problem with some invisible epsilon, since it is not really solvable short of interval arithmetic, and that's another story. Later, Andrew Mullhaupt