[Python-ideas] Fwd: Trigonometry in degrees
Tim Peters
tim.peters at gmail.com
Sun Jun 17 01:57:24 EDT 2018
[Steven D'Aprano <steve at pearwood.info>]
> Thanks Tim!
>
You're welcome ;-)
> Reading your digressions on the minutia of floating point maths is
> certainly an education. It makes algebra and real-valued mathematics
> seem easy in comparison.
>
Hard to say, really. The problem with floating point is that it's so
God-awful lumpy - special cases all over the place. Signaling and quiet
NaNs; signed infinities; signed zeroes; normal finites all with the same
number of bits, but where the gap between numbers changes abruptly at
power-of-2 boundaries; subnormals where the gap remains the same across
power-of-2 boundaries, but the number of _bits_ changes abruptly; all "the
rules" break down when you get too close to overflow or underflow; four
rounding modes to worry about; and a whole pile of technically defined
exceptional conditions and related traps & flags.
Ignoring all that, though, it's pretty easy ;-) 754 was dead serious about
requiring results act is if a single rounding is done to the infinitely
precise result, and that actually allows great simplification in reasoning.
The trend these days appears to be using automated theorem-proving systems
to keep track of the mountain of interacting special cases. Those have
advanced enough that we may even be on the edge of getting
provably-correctly-rounded transcendental functions with reasonable speed.
Although it's not clear people will be able to understand the proofs ;-)
I still haven't got over Mark Dickinson's demonstration a few years
> back that under Decimal floating point, but not binary, it is possible
> for the ordinary arithmetic average (x+y)/2 to be outside of the
> range [x, y]:
>
> py> from decimal import getcontext, Decimal
> py> getcontext().prec = 3
> py> x = Decimal('0.516')
> py> y = Decimal('0.518')
> py> (x + y) / 2
> Decimal('0.515')
>
Ya, decimal fp doesn't really solve anything except the shallow surprise
that decimal fractions generally aren't exactly representable as binary
fractions. Which is worth a whole lot for casual users, but doesn't
address any of the deep problems (to the contrary, it makes those a bit
worse).
I like to illustrate the above with 1-digit decimal fp, because it makes it
more apparent at once that - unlike as in binary fp - multiplication and
division by 2 may _not_ be exact in decimal fp. We can't even average a
number "with itself" reliably:
>>> import decimal
>>> decimal.getcontext().prec = 1
>>> x = y = decimal.Decimal(8); (x+y)/2 # 10 is much bigger than 8
Decimal('1E+1')
>>> x = y = decimal.Decimal(7); (x+y)/2 # 5 is much smaller than 7
Decimal('5')
But related things _can_ happen in binary fp too! You have to be near the
edge of representable non-zero finites though:
>>> x = y = 1e308
>>> x
1e+308
>>> (x+y)/2
inf
Oops. So rewrite it:
>>> x/2 + y/2
1e+308
Better! But then:
>>> x = y = float.fromhex("3p-1074")
>>> x
1.5e-323
>>> x/2 + y/2
2e-323
Oops. A math library has to deal with everything "correctly". Believe it
or not, this paper
"How do you compute the midpoint of an interval?"
https://hal.archives-ouvertes.fr/hal-00576641v1/document
is solely concerned with computing the average of two IEEE doubles, yet
runs to 29(!) pages. Almost everything you try fails for _some_ goofy
cases.
I personally write it as (x+y)/2 anyway ;-)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20180617/0e572913/attachment-0001.html>
More information about the Python-ideas
mailing list