Search code examples
pythonfloating-pointarithmetic-expressions

Is Python's == an equivalence relation on the floats?


In native Python, without using NumPy (for which numpy.nan != numpy.nan) there is no NaN, so am I right in thinking that Python's floating point == is reflexive? Then since it is symmetric (a == b implies b == a) and transitive (if a==b and b==c then a==c), can we say that Python's == is an equivalence relation on the floats?

EDIT: OK, so I learned that there is a NaN: float('nan') (thanks @unutbu) which will propagate through various operations, but does any native Python method return it (rather than raising an Exception) without me introducing it by this assignment?


Solution

  • == is reflexive for all numbers, zero, -zero, ininity, and -infinity, but not for nan.

    You can get inf, -inf, and nan in native Python just by arithmetic operations on literals, like below.

    These behave correctly, as in IEEE 754 and without math domain exception:

    >>> 1e1000 == 1e1000
    True
    >>> 1e1000/1e1000 == 1e1000/1e1000
    False
    

    1e1000 is a very big number, so float and double represent it as an infinity.

    • infinity is equal to infinity
    • infinity divided by infinity is not a number
    • not a number != not a number

    Floating-point arithmetic in Python also works OK for infinity minus infinity etc.:

    >>> x = 1e1000
    >>> x
    inf
    >>> x+x
    inf
    >>> x-x
    nan
    >>> x*2
    inf
    >>> x == x
    True
    >>> x-x == x-x
    False
    >>> 
    

    And for the zero and minus zero case:

    >>> inf = float("inf")
    >>> 1/inf
    0.0
    >>> -1/inf
    -0.0
    >>> -1/inf == 1/inf
    True
    >>>