[Python-ideas] math.inf and math.nan constants

Chris Angelico rosuav at gmail.com
Fri Jan 9 13:12:26 CET 2015


On Fri, Jan 9, 2015 at 10:58 PM, Alexander Heger <python at 2sn.net> wrote:
> here another odd issue related to NaN arithmetics:
>
> (1)
>>>> nan = float('nan')
>>>> nan is nan
> True
>>>> nan == nan
> False
>
> this is what we want.  Good. But
>
> (2)
>>>> x = (nan,)
>>>> x is x
> True
>>>> x == x
> True
>
> ... hmm ... apparently the comparison uses ID before using == ? for
> tuple elements?

It doesn't even compare them. Consider:

>>> class Different:
...  def __eq__(self, other):
...   print("Comparing",id(self),"with",id(other))
...   return False
...
>>> x = Different()
>>> x == x
Comparing 139945362930712 with 139945362930712
False
>>> tup = x,
>>> tup == tup
True

A tuple is equal to itself, for efficiency's sake, and doesn't go in
and check that all its elements are equal to themselves.

> on the other hand
>
> (3)
>>>> (nan,) is (nan,)
> False
>>>> (nan,) == (nan,)
> True

This, however, shows your point better. Likewise, using my Different
class shows that the comparison isn't made:

>>> (x,) is (x,)
False
>>> (x,) == (x,)
True

> I guess we see from
>
> (4)
>>>> float('nan') is float('nan')
> False
>>>> (float('nan'),) == (float('nan'),)
> False

Right; they're different objects, so the short-cut isn't taken.

It's a shortcut that works safely for every sane object except NaN.
You won't find many non-buggy objects that aren't equal to themselves.

> I understand why they all give the results they do, however, I think
> the second comparison in (2) should give False and, more importantly,
> the first comparison of (4) should be True - maths.nan should be a
> singleton - even if we allow to float.make_nan() to produce NaNs with
> different payloads - but maths.nan could be just one thing, one
> instance, the numerical counterpart to None.

Why should math.nan be a singleton? Consider:

>>> float("1.0") is float("1.0")
False
>>> (float("1.0"),) == (float("1.0"),)
True

Even with integers, although CPython caches some small ones:

>>> int("12345") is int("12345")
False
>>> (int("12345"),) == (int("12345"),)
True

(And CPython also caches literals, so both these tests have to use
explicit constructor calls.)

I think we can all agree that the number 12345 is unique - there
aren't two such numbers. So if we're allowed to have two int objects
representing the exact same number, why should NaN (which represents
the vastly infinite space of non-numbers) be unique?

ChrisA


More information about the Python-ideas mailing list