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
--
http://mail.python.org/mailman/listinfo/python-list