[Python-Dev] Not-a-Number (was PyObject_RichCompareBool identity shortcut) (original) (raw)

Steven D'Aprano steve at pearwood.info
Thu Apr 28 16:58:08 CEST 2011


Mark Shannon wrote:

Related to the discussion on "Not a Number" can I point out a few things that have not be explicitly addressed so far.

The IEEE standard is about hardware and bit patterns, rather than types and values so may not be entirely appropriate for high-level language like Python.

I would argue that the implementation of NANs is irrelevant. If NANs are useful in hardware floats -- and I think they are -- then they're just as equally useful as objects, or as strings in languages like REXX or Hypertalk where all data is stored as strings, or as quantum wave functions in some future quantum computer.

NaN is not a number (the clue is in the name). Python treats it as if it were a number:

>>> import numbers >>> isinstance(nan, numbers.Number) True Can be read as "'Not a Number' is a Number" ;)

I see your wink, but what do you make of these?

class NotAnObject(object): pass

nao = NotAnObject() assert isinstance(nao, object)

class NotAType(object): pass

assert type(NotAType) is type

NaN does not have to be a float or a Decimal. Perhaps it should have its own class.

Others have already pointed out this won't make any difference.

Fundamentally, the problem is that some containers bypass equality tests for identity tests. There may be good reasons for that shortcut, but it leads to problems with any object that does not define equality to be reflexive, not just NANs.

class Null: ... def eq(self, other): ... return False ... null = Null() null == null False [null] == [null] True

The default comparisons will then work as expected for collections. (No doubt, making NaN a new class will cause a whole new set of problems)

As pointed out by Meyer: NaN == NaN is False is no more logical than NaN != NaN is False

I don't agree with this argument. I think Meyer is completely mistaken there. The question of NAN equality is that of a vacuous truth, quite similar to the Present King of France:

http://en.wikipedia.org/wiki/Present_King_of_France

Meyer would have us accept that:

 The present King of France is a talking horse

and

 The present King of France is not a talking horse

are equally (pun not intended) valid. No, no they're not. I don't know much about who the King of France would be if France had a king, but I do know that he wouldn't be a talking horse.

Once you accept that NANs aren't equal to anything else, it becomes a matter of practicality beats purity to accept that they can't be equal to themselves either. A NAN doesn't represent a specific thing. It's a signal that your calculation has generated an indefinite, undefined, undetermined value. NANs aren't equal to anything. The fact that a NAN happens to have an existence as a bit-pattern at some location, or as a distinct object, is an implementation detail that is irrelevant. If you just happen by some fluke to compare a NAN to "itself", that shouldn't change the result of the comparison:

 The present King of France is the current male sovereign who
 rules France

is still false, even if you happen to write it like this:

 The present King of France is the present King of France

This might seem surprising to those who are used to reflexivity. Oh well. Just because reflexivity holds for actual things, doesn't mean it holds for, er, things that aren't things. NANs are things that aren't things.

Although both NaN == NaN and NaN != NaN could arguably be a "maybe" value, the all important reflexivity (x == x is True) is effectively part of the language. All collections rely on it and Python wouldn't be much use without dicts, tuples and lists.

Perhaps they shouldn't rely on it. Identity tests are an implementation detail. But in any case, reflexivity is not a guarantee of Python. With rich comparisons, you can define eq to do anything you like.

-- Steven



More information about the Python-Dev mailing list