How could I define trigonometric functions that take arguments in degrees instead of the usual radians, and compute correctly rounded results for these arguments?
Multiplying the argument by M_PI/180.0
before passing it to the corresponding function in radians does not work, because M_PI/180.0
is not π/180. Section 5.5 of the Handbook of Floating-Point Arithmetic offers a method to compute the correctly rounded product of the argument by π/180, but some arguments will still be such that this product is close to the midpoint between two consecutive representable floats, and then applying even a correctly rounded function in radians can produce the wrong final result.
Two strategies that may work alone or in combination are using higher precision and using the sinpi
,cospi
, tanpi
trigonometric functions from CRlibm, that compute respectively sin(πx)
, cos(πx)
and tan(πx)
.
For the latter strategy, there remains the problem of the division by 180, which is not exact for many arguments.
Regarding the higher-precision strategy (multiplying the argument by an extended-precision representation of π/180, then applying the extended-precision function in radians), there may remain a problem with “exact” cases. The theorem that states that the only rational results of sin
, cos
and tan
for a rational argument are obtained in 0
only applies to the radian versions. It obviously does not apply to the degree versions, and if for some floating-point input x, sindeg(x) is exactly the midpoint between two consecutive representable floating-point numbers, then no amount of intermediate precision is enough to guarantee that the final result is correctly rounded.
The only rationals q
for which cosdeg(360q)
is rational have 1, 2, 3, 4, or 6 as the denominator. This paper by Joerg Jahnel contains a short and beautiful proof using field theory in section 6. (Indeed, the author characterises the degree of the algebraic number cosdeg(360q)
using Euler's totient function.) So there is no floating-point q
such that cosdeg(360q)
is halfway between two adjacent floating-point numbers.
So I guess the answer is "about the same way you implement sin
and friends for radians," though @gnasher729 makes the excellent point that argument reduction for degrees is much, much nicer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With