[Python-Dev] Why is nan != nan?

Raymond Hettinger raymond.hettinger at gmail.com
Wed Mar 24 23:21:53 CET 2010

On Mar 24, 2010, at 2:31 PM, Alexander Belopolsky wrote:

> """
> In this context it doesn't particularly shock me that operations on
> NaN should cause invariant violations. After all, isn't NaN supposed
> to mean "not a number"? If it's not a number, it doesn't have to
> satisfy the properties of numbers.
> """

This sound like a good, universal reply to "bug reports" about
various containers/tools not working with NaNs :-)

Bug report: "Container X or Function Y doesn't behave well when I
give it a NaN as an input".

Closed -- Won't fix:  "It does not shock me that a NaN violates that
tool or container's invariants."

> To bring the discussion back on topic for python-dev, I would argue
> that reflexivity should hold for hashable values.  Having it otherwise
> would lead to unsurmountable problems when storing such values in sets
> or using them as keys in dictionaries.  If x == x is False stays for x
> = float('nan'), I would argue that hash(float('nan')) should raise
> NotImplemented or ValueError.

Hashability isn't the only place where you have a problem.
Even unordered collections are affected:

  >>> class ListBasedSet(collections.Set):
     ''' Alternate set implementation favoring space over speed
         and not requiring the set elements to be hashable. '''
     def __init__(self, iterable):
         self.elements = lst = []
         for value in iterable:
             if value not in lst:
     def __iter__(self):
         return iter(self.elements)
     def __contains__(self, value):
         return any(value == elem for elem in self.elements)
     def __len__(self):
         return len(self.elements)

>>> n = float('Nan')
>>> s = ListBasedSet([n])
>>> n in s                 # unexpected result
>>> len(s)                # expected result
>>> len(s & s)         # unexpected result

If we want to be able to reason about our programs,
then we need to rely on equality relations being
reflexsive, symmetric, and transitive.  Otherwise,
containers and functions can't even make minimal 
guarantees about what they do.

Anything else smells of a Douglas Hofstadter style
or Betrand Russell style logic bomb:

* this sentence is a lie
* this object isn't equal to itself
* this is a set containing sets that are not members of themselves

The property of NaN objects not being equal to themselves
is more harmful than helpful.  We should probably draw the
line at well-defined numeric contexts such as the decimal module
and stop trying to propagate NaN awareness throughout the
entire object model.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20100324/a4983fe4/attachment.html>

More information about the Python-Dev mailing list