float("nan") in set or as key

Robert Kern robert.kern at gmail.com
Sun Jun 5 15:44:23 EDT 2011


On 6/4/11 9:03 PM, Steven D'Aprano wrote:
> On Sat, 04 Jun 2011 16:49:40 -0500, Robert Kern wrote:
>
>> Steven is being a little hyperbolic. Python does not fully conform to
>> all of the details of the IEEE-754 specification, though it does conform
>> to most of them.
>
> I'm not sure that "most" is correct, but that depends on how you count
> the details. Let's just say it has partial support and let's not attempt
> to quantify it.

Fair enough. When I said "most", I was really counting in terms of operations 
that are actually performed, i.e. successful ones. If I have two regular 
floating point numbers x and y and add them together, the result is going to be 
what the IEEE-754 standard specifies almost all of the time. Almost every flop 
you actually do in Python will give you the IEEE-754 answer.

Of course, where Python tends to diverge is in the failure modes and error 
conditions. And also of course, the standard has more rules for all of those 
special cases, so saying that it conforms to "most of the rules" is not quite 
right, either.

> (Which is a big step up from how things were even just a few years ago,
> when there wasn't even a consistent way to create special values like INF
> and NAN. Many thanks to those who did that work, whoever you are!)
>
>
>> In particular, it raises an exception when you divide
>> by 0.0 when the IEEE-754 specification states that you ought to issue
>> the "divide by zero" or "invalid" signal depending on the numerator (and
>> which may be trapped by the user, but not by default) and will return
>> either an inf or a NaN value if not trapped. Thus, the canonical example
>> of a NaN-returning operation in fully-conforming IEEE-754 arithmetic,
>> 0.0/0.0, raises an exception in Python. You can generate a NaN by other
>> means, namely dividing inf/inf.
>
> But it's inconsistent and ad hoc. The guiding philosophy of Python
> floating point maths appears to be:
>
> (1) Python will always generate an exception on any failed operation, and
> never a NAN or INF (I believe I've even seen Guido explicitly state this
> as a design principle);

Well, if so, then it doesn't do it very well:

[~]
|2> inf = 1e300 * 1e300

[~]
|3> nan = inf / inf

[~]
|4> inf
inf

[~]
|5> nan
nan

> (2) arithmetic expressions and maths functions will usually, but not
> always, honour NANs and INFs if you provide then as input.
>
> I see this thread being driven by people who have failed to notice that
> (1) already applies, and so pure Python will never give them a NAN they
> didn't explicitly create themselves, but want to remove (2) as well.
 >
> Personally I think Python would be a better language if it *always*
> returned NANs and INFs for failed float operations, but I recognise that
> I'm in a minority and that many people will prefer exceptions. Even
> though I think Guido is wrong to believe that exceptions are more newbie
> friendly than NANs (my Hypercard experience tells me differently), I
> accept that opinions differ and I'm happy for exceptions to be the
> default behaviour.
>
> But it makes me rather annoyed when people who know nothing about
> IEEE-754 special values, their uses and justification, come along and
> insist that the only right answer is to throw away what little support
> for them we have.
>
>
>> One other deviation is the one which you were asking about. The standard
>> does say that the "invalid" signal should be issued in most
>> circumstances that generate a NaN and that the user should be able to
>> trap that signal. Python explicitly disables that mechanism. It used to
>> provide an optional module, fpectl, for providing a signal handler for
>> those. However, creating a handler for such a low-level signal in a
>> high-level language like Python is inherently unsafe, so it is not
>> really supported any more.
>
> More unsafe than ctypes?

More difficult to implement safely and more tempting to do unsafe things. If I 
remember correctly, I don't think you are supposed to allocate new memory inside 
such a signal handler. Of course, that's almost impossible to do in pure Python 
code.

> In any case, I believe that in Python, catching an exception is more or
> less the moral equivalent to trapping a low-level signal.

I agree.

>> The decimal module mostly gets it right. It translates the signals into
>> Python exceptions that can be disabled in a particular context.
>
> All I want for Christmas is for floats to offer the same level of
> IEEE-754 support as decimal, only faster. And a pony.

Hear-hear!

-- 
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
  that is made terrible by our own mad attempt to interpret it as though it had
  an underlying truth."
   -- Umberto Eco




More information about the Python-list mailing list