[Python-ideas] Yet another sum function (fractions.sum)
Oscar Benjamin
oscar.j.benjamin at gmail.com
Thu Aug 22 12:58:30 CEST 2013
On Aug 22, 2013 8:12 AM, "Chris Angelico" <rosuav at gmail.com> wrote:
>
> On Thu, Aug 22, 2013 at 1:02 PM, Mark Dickinson <dickinsm at gmail.com> wrote:
> > In that sense, I'd say that it's rather the ** operation that's the odd man
> > out, in that there are very few other ways to get complex numbers with no
> > obvious explicit request for complex numbers
>
> 1/2 == 0.5 # int/int --> float
> (-4.0)**0.5 == (-4.0)**0.5 == 1.2246467991473532e-16+2j #
> float**float --> complex
>
> (though why it doesn't equal 2j exactly, I don't know - surely there's
> enough precision in these floats to calculate that?)
__pow__ is less accurate than sqrt:
$ py -3.3
Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:03:43) [MSC v.1600
32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 4 ** .5
2.0
>>> (-4) ** .5
(1.2246467991473532e-16+2j)
>>> 1j * (4 ** .5)
2j
>>> import cmath
>>> cmath.sqrt(-4)
2j
>>> cmath.sqrt(-4.)
2j
sqrt and __pow__ for negative numbers use very different algorithms so
they give different results. IIUC (4.).__pow__(.5) is handled directly
by the FPU and (-4.).__pow__(.5) is handled in the CPython code base.
Clearly, though, it would be better if (-4)**.5 would be modified to
return 1j*(4**.5).
> Personally, I don't like the automated casting of int to float, since
> int covers arbitrary range and float will quietly lose precision; if
> you flick to float early in a calculation, you may be suddenly
> surprised by the inaccuracy at the end. But that's the decision
> Python's made, so it makes good sense for the upcasting of float to
> complex to work the same way - especially since you can't lose
> precision by going from float to complex (AFAIK)
If the int is out of range you'll get an error:
>>> 1.0 * (10 ** 1000)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: long int too large to convert to float
An implicit float conversion does not quietly lose precision. All
subsequent values are usually infected and get turned into floats. The
implicit float conversion only happens in two cases:
1) You mixed a float into your otherwise exact integer computation.
2) Division.
For case 1) the answer is just don't do this. It's usually possible to
spot when it's happened because your end result is a float. The
exceptions to this are if you're doing something like:
while m < n:
# do stuff
m = ... # Somehow a float can occasionally infect m
return n # But we don't return m
I think it would be good to be able to know that implicit conversions
wouldn't occur but I also dislike putting spurious decimal points
everywhere to ensure floating point computation e.g.:
x = x / 2. # Unnecessary in Python 3
Note that for loss of accuracy the implicit float conversion from
Python 3's true division gives a relative error of ~1e-16 which
usually corresponds to a similarly small absolute error. Python 2's
floor division has an absolute error of order 1 which is usually a
massive error for people who care about accuracy.
For me personally though I think that a conversion context would be useful e.g.:
with everything_is_exact_or_I_get_an_error():
# compute stuff
That would save me *a lot* of testing/debugging.
Oscar
More information about the Python-ideas
mailing list