Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there any floating-point comparison "anomalies"?

If I compare two floating-point numbers, are there cases where a>=b is not equivalent to b<=a and !(a<b), or where a==b is not equivalent to b==a and !(a!=b)?

In other words: are comparisons always "symmetrical", such that I can get the same result on a comparison by swapping the operands and mirroring the operator? And are they always "negatable", such that negating an operator (e.g. > to <=) is equivalent to to applying a logical NOT (!) to the result?

like image 233
mwfearnley Avatar asked Sep 13 '10 08:09

mwfearnley


People also ask

What are the limitations of floating point numbers?

As a result, they do not represent all of the same values, are not binary compatible, and have different associated error rates. Because of a lack of guarantees on the specifics of the underlying floating-point system, no assumptions can be made about either precision or range.

How accurate are floating point numbers?

With a data type, there is a limited number of bits. Those bits cannot accurately represent a value that requires more than that number of bits. The data type float has 24 bits of precision. This is equivalent to only about 7 decimal places.

Why should we never compare floating point values by using exact equality comparison?

Comparing for equality Floating point math is not exact. Simple values like 0.1 cannot be precisely represented using binary floating point numbers, and the limited precision of floating point numbers means that slight changes in the order of operations or the precision of intermediates can change the result.

Why do floating point errors occur?

It's a problem caused when the internal representation of floating-point numbers, which uses a fixed number of binary digits to represent a decimal number. It is difficult to represent some decimal number in binary, so in many cases, it leads to small roundoff errors.


2 Answers

Assuming IEEE-754 floating-point:

  • a >= b is always equivalent to b <= a.*
  • a >= b is equivalent to !(a < b), unless one or both of a or b is NaN.
  • a == b is always equivalent to b == a.*
  • a == b is equivalent to !(a != b), unless one or both of a or b is NaN.

More generally: trichotomy does not hold for floating-point numbers. Instead, a related property holds [IEEE-754 (1985) §5.7]:

Four mutually exclusive relations are possible: less than, equal, greater than, and unordered. The last case arises when at least one operand is NaN. Every NaN shall compare unordered with everything, including itself.

Note that this is not really an "anomaly" so much as a consequence of extending the arithmetic to be closed in a way that attempts to maintain consistency with real arithmetic when possible.

[*] true in abstract IEEE-754 arithmetic. In real usage, some compilers might cause this to be violated in rare cases as a result of doing computations with extended precision (MSVC, I'm looking at you). Now that most floating-point computation on the Intel architecture is done on SSE instead of x87, this is less of a concern (and it was always a bug from the standpoint of IEEE-754, anyway).

like image 86
Stephen Canon Avatar answered Jan 04 '23 05:01

Stephen Canon


In Python at least a>=b is not equivalent to !(a<b) when there is a NaN involved:

>>> a = float('nan')
>>> b = 0
>>> a >= b
False
>>> not (a < b)
True

I would imagine that this is also the case in most other languages.

Another thing that might surprise you is that NaN doesn't even compare equal to itself:

>>> a == a
False
like image 37
Mark Byers Avatar answered Jan 04 '23 03:01

Mark Byers