views:

668

answers:

6

In most cases, I understand that a floating point comparison test should be implemented using over a range of values (abs(x-y) < epsilon), but does self subtraction imply that the result will be zero?

// can the assertion be triggered?
float x = //?;
assert( x-x == 0 )

My guess is that nan/inf might be special cases, but I'm more interested in what happens for simple values.

edit:

I'm happy to pick an answer if someone can cite a reference (IEEE floating point standard)?

+3  A: 

Yes, apart from the special cases x-x will always be 0. But x*(1/x) will not always be 1 ;-)

ypnos
Isn't he asking for the special cases?
Frank Krueger
@Frank - Yes, but he's ignoring the two special cases ypnos is referring to (`inf` and `NaN`).
Chris Lutz
+3  A: 

Yes, self-subtraction should always result in zero, except for special cases.

The problem occurs where you add, subtract, multiply or divide before a comparison where the exponent and mantissa are adjusted. When the exponents are the same, the mantissas are subtracted, and if they're the same, everything ends up at zero.

http://grouper.ieee.org/groups/754/

WhirlWind
+41  A: 

As you hinted, inf - inf is NaN, which is not equal to zero. Similarly, NaN - NaN is NaN. It is true, however, that for any finite floating-point number x, x - x == 0.0 (depending on the rounding mode, the result of x - x might be negative zero, but negative zero compares equal to 0.0 in floating-point arithmetic).

Edit: it's a little tricky to give a clear standards reference, because this is an emergent property of the rules set forth in the IEEE-754 standard. Specifically, it follows from the requirement that operations defined in Clause 5 be correctly rounded. Subtraction is such an operation (Section 5.4.1 "Arithmetic operations"), and the correctly-rounded result of x - x is a zero of the appropriate sign (Section 6.3, paragraph 3):

When the sum of two operands with opposite signs (or the difference of two operands with like signs) is exactly zero, the sign of that sum (or difference) shall be +0 in all rounding-direction attributes except roundTowardNegative; under that attribute, the sign of an exact zero sum (or difference) shall be −0.

So the result of x - x must be +/- 0, and therefore must compare equal to 0.0 (Section 5.11, paragraph 2):

Comparisons shall ignore the sign of zero.

Further Edit: That's not to say that a buggy compiler couldn't cause that assert to fire. Your question is ambiguous; there is no finite floating point number x such that x - x == 0 is false. However, that's not what the code that you posted checks; it checks whether or not a certain expression in a C-style language can evaluate to a non-zero value; in particular, on certain platforms, with certain (ill-conceived) compiler optimizations, the two instances of the variable x in that expression might have different values, causing the assertion to fail (especially if x is the result of some computation, instead of a constant, representable value). This is a bug in the numerics model on those platforms, but that doesn't mean that it can't happen.

Stephen Canon
fantastic, exactly what I was looking for
Andrew Walker
+1. Whodathunk the internet could be this precise. (Not to take anything from you personally, Stephen.)
Potatoswatter
@Potatoswatter: it helps to have spent a few months as the editor of the 754 draft standard. Without that background, I wouldn't know where to look for this stuff.
Stephen Canon
Could you comment my code example from http://stackoverflow.com/questions/2686644/is-there-a-floating-point-value-of-x-for-which-x-x-0-is-false/2687323#2687323. Thanks.
Oleg
Of course, neither C nor C++ _requires_ 754. Perhaps the question should be retagged ?
MSalters
A truly awesome answer
Andras Zoltan
Also, if x is global and volatile, the compiler might read it twice, and multithreading could interfere.
Robert Fraser
Oh the days when the internet was filled with this quality of information... 1993. Far less information, but high quality :-)
phkahler
@MSalters: an excellent point.
Stephen Canon
+4  A: 

If the representation is transformed (for example from 64-bit memory format to 80-bit internal register format on x86) I would expect that the assertion could possibly fire in some circumstances.

Mark B
As the question is worded, this case is probably impossible. But `x=a+b; assert(x-(a+b)==0)` might trigger it.
Mark Ransom
I think this is a key thing to be concerned with - the expression `x - x` is unlikely to be be used in real code (why would you?), But subtracting (or comparing) a variable's value with an expression that might have produced that value might happen, and might produce unexpected results because of how the compiler might handle precisions of intermediate values. See http://stackoverflow.com/questions/2497825/gcc-problem-with-raw-double-type-comparisons for an example that's probably not too unlike something that might happen in the real world.
Michael Burr
+1  A: 

Regarding what Mark says -- check out this link http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.18 . (Not sure if it applies to your situation though.)

Bus
+3  A: 
Oleg