math.nroot [was Re: A brief question.]

Tim Peters tim.peters at gmail.com
Tue Jul 5 10:52:29 EDT 2005


[Tim Peters]
>> All Python behavior in the presence of infinities, NaNs, and signed
>> zeroes is a platform-dependent accident, mostly inherited from that
>> all C89 behavior in the presence of infinities, NaNs, and signed
>> zeroes is a platform-dependent crapshoot.
 
[Michael Hudson]
> As you may have noticed by now, I'd kind of like to stop you saying
> this :) -- at least on platforms where doubles are good old-fashioned
> 754 8-byte values.

Nope, I hadn't noticed!  I'll stop saying it when it stops being true,
though <wink>.  Note that since there's not even an alpha out for 2.5
yet, none of the good stuff you did in CVS counts for users yet.

> But first, I'm going to whinge a bit, and lay out some stuff that Tim
> at least already knows (and maybe get some stuff wrong, we'll see).
>
> Floating point standards lay out a number of "conditions": Overflow
> (number too large in magnitude to represent), Underflow (non-zero
> number to small in magnitude to represent), Subnormal (non-zero number
> to small in magnitude to represent in a normalized way), ...

The 754 standard has five of them:  underflow, overflow, invalid
operation, inexact, and "divide by 0" (which should be understood more
generally as a singularity; e.g., divide-by-0 is also appropriate for
log(0)).

> For each condition, it should (at some level) is possible to trap each
> condition, or continue in some standard-mandated way (e.g. return 0
> for Underflow).

754 requires that, yes.

> While ignoring the issue of allowing the user to control this, I do
> wish sometimes that Python would make up it's mind about what it does
> for each condition.

Guido and I agreed long ago that Python "should", by default, raise an
exception on overflow, invalid operation, and divide by 0, and "should
not", by default, raise an exception on underflow or inexact.  Such
defaults favor non-expert use.  Experts may or may not be happy with
them, so Python "should" also allow changing the set.

> There are a bunch of conditions which we shouldn't and don't trap by
> default -- Underflow for example.  For the conditions that probably should
> result in an exception, there are inconsistencies galore:

> >>> inf = 1e300 * 1e300 # <- Overflow, no exception
> >>> nan = inf/inf # <- InvalidOperation, no exception

Meaning you're running on a 754 platform whose C runtime arranged to
disable the overflow and invalid operation traps.  You're seeing
native HW fp behavior then.

> >>> pow(1e100, 100) <- Overflow, exception
> Traceback (most recent call last):
>  File "<stdin>", line 1, in ?
> OverflowError: (34, 'Numerical result out of range')
> >>> math.sqrt(-1) # <- InvalidOperation, exception
> Traceback (most recent call last):
>  File "<stdin>", line 1, in ?
> ValueError: math domain error

Unlike the first two examples, these call libm functions.  Then it's a
x-platform crapshoot whether and when the libm functions set errno to
ERANGE or EDOM, and somewhat of a mystery whether it's better to
reproduce what the native libm considers to be "an error", or try to
give the same results across platforms.  Python makes a weak attempt
at the latter.

> At least we're fairly consistent on DivisionByZero...

When it's a division by 0, yes.  It's cheap and easy to test for that.
 However, many expert uses strongly favor getting back an infinity
then instead, so it's not good that Python doesn't support a choice
about x/0.

> If we're going to trap Overflow consistently, we really need a way of
> getting the special values reliably -- which is what pep 754 is about,
> and its implementation may actually work more reliably in 2.5 since my
> recent work...

I don't know what you have in mind.  For example, checking the result
of x*y to see whether it's an infinity is not a reliable way to detect
overflow, and it fails in more than one way (e.g., one of the inputs
may have been an infinity (in which case OverflowError is
inappropriate), and overflow doesn't always result in an infinity
either (depends on the rounding mode in effect)).

> On the issue of platforms that start up processes with traps enabled,
> I think the correct solution is to find the incantation to turn them
> off again and use that in Py_Initialize(), though that might upset
> embedders.

Hard to know.  Python currently has a hack to disable traps on
FreeBSD, in python.c's main().



More information about the Python-list mailing list