I propose to add the functions scipy.special.sinpi, cospi, tanpi, and cotpi. Appreciate if you could share your thoughts!
These functions compute the respective trigonometric functions for real arguments expressed in number of “pi”s. The first three are specified in IEEE 754-2019 Section 9.2; the last one (cotpi) an be defined in terms of 1/tanPi and is provided to avoid unnecessary floating point exceptions.
A particular use case is gh-20761, where the inverse CDF of the Cauchy distribution at probability p involves cotpi(p). Use cases for the first three functions should be abundant given that they are standardized by IEEE.
Similar functions in SciPy include sindg (scipy.special.sindg — SciPy v1.13.0 Manual) and related functions, which take arguments in degrees. The current implementation does not adhere to IEEE specification (modulo the scaling), though it is not difficult to make them so (gh-20731). However, if the IEEE functions are added to SciPy, then the dg functions can become simple wrappers.
The downside of adding these functions is increased maintenance. One possible implementation is to first do range reduction (using fmod) and then convert to radian and call the C library’s trigonometric functions. Considering the dg functions can delegate to the pi functions, the overall increase of maintenance burden is marginal.
In summary, I believe adding these functions will benefit the users of SciPy and in turn strengthen SciPy’s position in scientific computing for Python.
The sindg and cosdg functions of SciPy wrap those from cephes. The implementation reduces the arguments to +/- 45 degrees, convert the result to radians, and then plug into a polynomial (might be Taylor series but I didn’t verify).
The tandg and cotdg functions originally wrapped those from cephes, but now calls the tan function of C library directly.
Either approach would be fine for implementing the -pi functions. There might be a polynomial with better precision than converting to radians, but I haven’t taken the effort to explore this as I expect the precision with radians to be sufficient.
I am personally on the same opinion as Albert. sinpi is enough. Everything we add to the public API has a non negligible cost so we have to be mindful about that.
Indeed we already have numpy.sin and scipy.special.sindg; adding scipy.special.sinpi would look “crowded”. It would have been nice if there were no scipy.special.sindg function
I checked the spec of IEEE tanPi; it does agree with sinPi/cosPi in terms of signed zero and infinity. So yes, adding sinPi and cosPi would be minimally sufficient.
In fact, sinPi and cosPi are already defined in IEEE 754-2008, while tanPi only made its way into IEEE 754-2019. Apparently the tanPi function had some technical difficulty for standardization; see https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/tanpi.txt for a discussion. But the linked post doesn’t explain why and how tanPi got into IEEE 754-2019.
Adding special.sinpi and special.cospi seems very reasonable to me. There was also support in the linked mailing list thread, so I’d say all lights on green for those two. I don’t have a strong opinion on tanpi.
As the linked post points out, SciPy already contains _sinpi and _cospi, and I checked they follow IEEE’s spec. There are already test cases for them too!
Let me make a PR to promote these two functions to public and add some docs. Will omit tanpi and cotpi for now. I guess those function are defined by IEEE for efficiency and possibly accuracy, but I haven’t done more analysis to support that guess.
+1 for sinpi and cospi (and I would be happy with also including tanpi and cotpi for completeness and consistency–namespaces have plenty of room for useful functions, even if they are simple) . It would be nice if special.sinc was called sincpi, but so it goes.