[Python-ideas] Fwd: Trigonometry in degrees
Tim Peters
tim.peters at gmail.com
Tue Jun 12 01:50:56 EDT 2018
[Steven D'Aprano]
> ...
The initial proposal is fine: a separate set of trig functions that take
> their arguments in degrees would have no unexpected surprises (only the
> expected ones). With a decent implementation i.e. not this one:
>
> # don't do this
> def sind(angle):
> return math.sin(math.radians(angle))
>
But that's good enough for almost all real purposes. Indeed, except for
argument reduction, it's essentially how scipy's sindg and cosdg _are_
implemented:
https://github.com/scipy/scipy/blob/master/scipy/special/cephes/sindg.c
> and equivalent for cos, we ought to be able to get correctly rounded
> values for nearly all the "interesting" angles of the circle, without
> those pesky rounding issues caused by π not being exactly representable
> as a float.
>
> If people are overly ;-) worried about tiny rounding errors, just compute
things with some extra bits of precision to absorb them. For example,
install `mpmath` and use this:
def sindg(d):
import math, mpmath
d = math.fmod(d, 360.0)
if abs(d) == 180.0:
return 0.0
with mpmath.extraprec(12):
return float(mpmath.sin(mpmath.radians(d)))
Then, e.g,
>>> for x in (0, 30, 90, 150, 180, 210, 270, 330, 360):
... print(x, sindg(x))
0 0.0
30 0.5
90 1.0
150 0.5
180 0.0
210 -0.5
270 -1.0
330 -0.5
360 0.0
Notes:
1. Python's float "%" is unsuitable for argument reduction; e.g.,
>>> -1e-14 % 360.0
360.0
`math.fmod` is suitable, because it's exact:
>>> math.fmod(-1e-14, 360.0)
-1e-14
2. Using a dozen extra bits of precision make it very likely you'll get the
correctly rounded 53-bit result; it will almost certainly (barring bugs in
`mpmath`) always be good to less than 1 ULP.
3. Except for +-180. No matter how many bits of float precision (including
the number of bits used to approximate pi) are used, converting that to
radians can never yield the mathematical `pi`; and sin(pi+x) is
approximately equal to -x for tiny |x|; e.g., here with a thousand bits:
>>> mpmath.mp.prec = 1000
>>> float(mpmath.sin(mpmath.radians(180)))
1.2515440597544546e-301
So +-180 is special-cased. For cosdg, +-{90. 270} would need to be
special-cased for the same reason.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20180612/3dc67858/attachment-0001.html>
More information about the Python-ideas
mailing list