On 10 October 2012 02:14, Steven D'Aprano <steve@pearwood.info> wrote:
On 10/10/12 09:13, Joshua Landau wrote:
Just a curiosity here (as I can guess of plausible reasons myself, so there
probably are some official stances).

Is there a reason NaNs are not instances of NaN class?

Because that would complicate Python's using floats for absolutely no benefit.
Instead of float operations always returning a float, they would have to return
a float or a NAN. To check for a valid floating point instance, instead of
saying:

isinstance(x, float)

you would have to say:

isinstance(x, (float, NAN))
 
Not the way I'm proposing it.

>>> class NAN(float):
...     def __new__(self):
...             return float.__new__(self, "nan")
...     def __eq__(self, other):
...             return other is self
... 
>>> isinstance(NAN(), float)
True
>>> NAN() is NAN()
False
>>> NAN() == NAN()
False
>>> x = NAN()
>>> x is x
True
>>> x == x
True
>>> x
nan

 
And what about infinities, denorm numbers, and negative zero? Do they get
dedicated classes too?

Infinities? No, although they might well if the infinities were different (set of reals vs set of ints, for example).
Denorms? No, that's a completely different thing.
-0.0? No, that's a completely different thing.
 
I was asking, because instances of a class maps on to a behavior that matches *almost exactly* what *both* parties want, why was it not used? This is not the case with anything other than that.

And what is the point of this added complexity? Nothing.

Simplicity. It's simpler.
 
You *still* have the rule that "x == x for all x, except for NANs".

False. I was proposing that x == x but NAN() != NAN().
 
The only difference is that "NANs" now means "instances of NAN class" rather than
"NAN floats" (and Decimals).

False, if you subclass float.
 
Working with IEEE 754 floats is now far more of
a nuisance because some valid floating point values aren't floats but have a
different class, but nothing meaningful is different.
 
Then x == x would be True (as they want), but [this NaN] == [that NaN]
would be False, as expected.

Making NANs their own class wouldn't give you that. If we wanted that
behaviour, we could have it without introducing a NAN class: just change the
list __eq__ method to scan the list for a NAN using math.isnan before checking
whether the lists were identical.

False.

>>> x == x
True
>>> [NAN()] == [NAN()]
False

as per my previous "implementation".
 
But that would defeat the purpose of the identity check (an optimization to
avoid scanning the list)! Replacing math.isnan with isinstance doesn't change
that.


I guess that raises the question about why x == x but sqrt(-1) != sqrt(-1),

That question has already been raised, and answered, repeatedly in this thread.
 
False. x != x, so that has not been "answered". This was an example problem with my own suggested implementation.

but it seems a lot less of a big deal than all of the exceptions with
container equalities.

Container equalities are not a big deal. I'm not sure what problem you think
you are solving.

 Why would you assume that? I mentioned it from honest curiosity, and all I got back was an attack. Please, I want to be civil but you need to act less angrily.

[Has not been spell-checked, as I don't really have time </lie>]

Thank you for your time, even though I disagree,

Joshua Landau