Turn off ZeroDivisionError?

M

Mark Dickinson

Exactly.  Espeically when Python supposedly leaves floating
point ops up to the platform.

There's a thread at http://mail.python.org/pipermail/python-list/2005-July/329849.html
that's quite relevant to this discussion. See especially the
exchanges between Michael
Hudson and Tim Peters in the later part of the thread. I like this
bit, from Tim:

"I believe Python should raise exceptions in these cases by default,
because, as above, they correspond to the overflow and
invalid-operation signals respectively, and Python should raise
exceptions on the overflow, invalid-operation, and divide-by-0
signals
by default. But I also believe Python _dare not_ do so unless it
also
supplies sane machinery for disabling traps on specific signals
(along
the lines of the relevant standards here). Many serious numeric
programmers would be livid, and justifiably so, if they couldn't get
non-stop mode back. The most likely x-platfrom accident so far is
that they've been getting non-stop mode in Python since its
beginning."

Mark
 
B

Ben Finney

Mark Dickinson said:
But not everyone wants 1./0. to produce an infinity; some people
would prefer an exception.

Special cases aren't special enough to break the rules.

Most people would not want this behaviour either::
0.10000000000000001

But the justification for this violation of surprise is "Python just
does whatever the underlying hardware does with floating-point
numbers". If that's the rule, it shouldn't be broken in the special
case of division by zero.
 
C

Christian Heimes

Grant said:
A more efficient implementation? Just delete the code that
raises the exception and the HW will do the right thing.

Do you really think that the hardware and the C runtime library will do
the right thing? Python runs on a lots platforms and architectures. Some
of the platforms don't have a FPU or don't support hardware acceleration
for floating point ops for user space applications. Some platforms don't
follow IEEE 754 semantics at all.

It took us a lot of effort to get consistent results for edge cases of
basic functions like sin and atan on all platforms. Simply removing
those lines and praying that it works won't do it.

Christian
 
N

Neal Becker

Christian said:
Do you really think that the hardware and the C runtime library will do
the right thing? Python runs on a lots platforms and architectures. Some
of the platforms don't have a FPU or don't support hardware acceleration
for floating point ops for user space applications. Some platforms don't
follow IEEE 754 semantics at all.

It took us a lot of effort to get consistent results for edge cases of
basic functions like sin and atan on all platforms. Simply removing
those lines and praying that it works won't do it.

Christian

I think, ideally, that on a platform that has proper IEEE 754 support we
would rely on the hardware, and only on platforms that don't would we add
extra software emulation.

With proper hardware support, the default would be a hardware floating pt
exception, which python would translate.

If the user wanted, she should be able to turn it off during some
calculation (but that would not be the default).
 
C

Carl Banks

Special cases aren't special enough to break the rules.

Most people would not want this behaviour either::

0.10000000000000001

But the justification for this violation of surprise is "Python just
does whatever the underlying hardware does with floating-point
numbers". If that's the rule, it shouldn't be broken in the special
case of division by zero.

Do you recall what the very next Zen after "Special cases aren't
special enough to break the rules" is?


that's-why-they-call-it-Zen-ly yr's,

Carl Banks
 
G

Grant Edwards

Special cases aren't special enough to break the rules.

Most people would not want this behaviour either::

0.10000000000000001

But the justification for this violation of surprise is
"Python just does whatever the underlying hardware does with
floating-point numbers". If that's the rule, it shouldn't be
broken in the special case of division by zero.

My feelings exactly.

That's the rule that's always quoted to people asking about
various FP weirdness, but apparently the rule only applies
when/where certain people feel like it.
 
G

Grant Edwards

Python's a/0 outcome doesn't violate the standards

It does.
because Python doesn't promise to follow the IEEE 754 standard in the first place.

Whether a certain behavior violates that standard is
independant of whether somebody promised to follow the standard
or not.
Mark and I are working hard to make math in Python more
reliable across platforms. So far we have fixed a lot of
problems but we haven't discussed the a/0 matter.

The best we could give you is an option that makes Python's floats more
IEEE 754 like:

... r = a/0
... print r
inf

That would be great.
 
C

Carl Banks

I've always found that check to be really annoying. Every time
anybody asks about floating point handling, the standard
response is that "Python just does whatever the underlying
platform does". Except it doesn't in cases like this. All my
platforms do exactly what I want for division by zero: they
generate a properly signed INF. Python chooses to override
that (IMO correct) platform behavior with something surprising.
Python doesn't generate exceptions for other floating point
"events" -- why the inconsistency with divide by zero?

I understand your pain, but Python, like any good general-purpose
language, is a compromise. For the vast majority of programming,
division by zero is a mistake and not merely a degenerate case, so
Python decided to treat it like one.


Carl Banks
 
M

Mark Dickinson

Most people would not want this behaviour either::

    >>> 0.1
    0.10000000000000001

Sure. And if it weren't for backwards-compatibility and speed issues
one
could reasonably propose making Decimal the default floating-point
type
in Python (whilst still giving access to the hardware binary floating
point).
I dare say that the backwards-compatibility isn't really a problem: I
can
imagine a migration strategy resulting in Decimal default floats in
Python 4.0 ;-). But there are orders-of-magnitude differences in
speed
that aren't going to be solved by merely rewriting decimal.py in C.

I guess it's all about tradeoffs.
But the justification for this violation of surprise is "Python just
does whatever the underlying hardware does with floating-point
numbers". If that's the rule, it shouldn't be broken in the special
case of division by zero.

I'm not convinced that this is really the justification, but I'm not
quite sure
what we're talking about here. The justification for *printing*
0.1000...1 instead
of 0.1 has to do with not hiding binary floating-point strangeness
from users, since
they're eventually going to have to deal with it anyway, and hiding it
arguably
causes worse difficulties in understanding. The justification for
having
the literal 0.1 not *be* exactly the number 0.1: well, what are the
alternatives?
Decimal and Rational are very slow in comparison with float, and
historically
Decimal wasn't even available until recently.

Mark
 
M

Mark Dickinson

I understand your pain, but Python, like any good general-purpose
language, is a compromise.  For the vast majority of programming,
division by zero is a mistake and not merely a degenerate case, so
Python decided to treat it like one.

Agreed. For 'normal' users, who haven't encountered the ideas of
infinities and NaNs, floating-point numbers are essentially a
computational model for the real numbers, and operations that are
illegal in the reals (square root of -1, division by zero) should
produce Python exceptions rather than send those users hurrying to
comp.lang.python to complain about something called #IND appearing on
their screens.

But for numerically-aware users it would be nice if it were possible
to do non-stop IEEE arithmetic with infinities and NaNs.

Any suggestions about how to achieve the above-described state of
affairs are welcome!

Mark
 
C

Christian Heimes

Mark said:
Any suggestions about how to achieve the above-described state of
affairs are welcome!

I have worked out a suggestion in three parts.

Part 1
------

The PyFloat C API gets two more functions:

int PyFloat_SetIEEE754(int new_state) -> old state
int PyFloat_GetIEEE754(void) -> current state

By default the state is 0 which means no IEEE 754 return values for
1./0., 0./0. and maybe some other places. An op like 1./0. raises an
exception.

With state 1 float ops like f/0. returns copysign(INF, f) and for f=0.
it returns a NaN.

ints and longs aren't affected by the state.

The state is to be stored and fetched from Python's thread state object.
This could slow down floats a bit because every time f/0. occurs the
state has to be looked up in the thread state object.

Part 2
------

The two function are exposed to Python code as math.set_ieee754 and
math.get_ieee754. As an alternative the functions could be added to a
new module ieee754 or to the float type.

Part 3
------

contextlib gets a new context for ieee754

class ieee754(object):
def __init__(self, state=1):
self.new_state = state

def __enter__(self):
self.old_state = math.set_ieee754(self.new_state)

def __exit__(self, *args):
math.set_ieee754(self.old_state)

usage:

with contextlib.ieee754():
...

Christian
 
M

Mark Dickinson

That would be great.

Seriously, in some of my crazier moments I've considered trying to
write a PEP on this, so I'm very interested in figuring out exactly
what it is that people want. The devil's in the details, but the
basic ideas would be:

(1) aim for consistent behaviour across platforms in preference to
exposing differences between platforms
(2) make default arithmetic raise Python exceptions in preference to
returning infs and nans. Essentially, ValueError would be raised
anywhere that IEEE 754(r) specifies raising the divide-by-zero or
invalid signals, and OverflowError would be raised anywhere that IEEE
754(r) specifies raising the overflow signal. The underflow and
inexact signals would be ignored.
(3) have a thread-local floating-point environment available from
Python to make it possible to turn nonstop mode on or off, with the
default being off. Possibly make it possible to trap individual
flags.

Any thoughts on the general directions here? It's far too late to
think about this for Python 2.6 or 3.0, but 3.1 might be a possibility.
 
G

greg

Christian said:
I'm not talking about CS and IEEE floating point ops. I was referring to
plain good old math. Python targets both newbies and professionals.

Maybe there should be another division operator for
use by FP professionals?

/ --> mathematical real division
// --> mathematical integer division
/// --> IEEE floating point division (where supported)
 
G

greg

Christian said:
The state is to be stored and fetched from Python's thread state object.
This could slow down floats a bit because every time f/0. occurs the
state has to be looked up in the thread state object.

An alternative implementation might be to leave zero division
traps turned on, and when one occurs, consult the state to
determine whether to raise an exception or re-try that
operation with trapping turned off.

That would only incur the overhead of changing the hardware
setting when a zero division occurs, which presumably is a
relatively rare occurrence.
 
S

Steven D'Aprano

I'm not talking about CS and IEEE floating point ops. I was referring to
plain good old math. Python targets both newbies and professionals.
That's the reason for two math modules (math and cmath).

Alas, Python doesn't do "plain good old math" either:
0

Hmmm... okay, let's try this:
False

How about something a little more advanced? Euler's Identity says that e
to the power of i*pi equals -1. Python writes i as j, so we write this:
False

How about something absolutely fundamental to good old maths, like the
Distributive Law?
False

Or even something as basic as this:
False


Floating point maths is not and can not be the same as the maths we learn
about in schools. Floats are not reals. We should just give up the
fantasy of making floats the same as real numbers, because it cannot
happen. I applaud the effort to hide the complexity of floating point
maths, but compared to the things newbies already get surprised by,
having 1.0/0 return inf isn't even a blip on the radar.

In fact, most school kids learn that "one over nothing is infinity" (not
from their teachers, I think they pick it up by osmosis), so that will
probably cause less grief than the other examples I gave.



[...]
Python's a/0 outcome doesn't violate the standards because Python
doesn't promise to follow the IEEE 754 standard in the first place. Mark
and I are working hard to make math in Python more reliable across
platforms. So far we have fixed a lot of problems but we haven't
discussed the a/0 matter.

And thank you for your efforts, they are appreciated.

The best we could give you is an option that makes Python's floats more
IEEE 754 like:

... r = a/0
... print r
inf


Sounds like a good plan to me. I could live with that.
 
N

Neal Becker

Mark said:
How about platforms that don't even have nans? I don't think either
IBM's hexadecimal floating-point format, or the VAX floating-point
formats
support NaNs. Python doesn't assume IEEE 754 hardware; though much
of its code
could be a lot simpler if it did :).
rywhere ;-).

Mark

So just use it where it's available, and emulate where it's not.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top