diff --git a/Misc/NEWS.d/next/Library/2026-07-19-19-05-00.gh-issue-154146.acospi.rst b/Misc/NEWS.d/next/Library/2026-07-19-19-05-00.gh-issue-154146.acospi.rst new file mode 100644 index 00000000000000..5dbddbadee0bd3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-19-19-05-00.gh-issue-154146.acospi.rst @@ -0,0 +1,2 @@ +Fix accuracy of :func:`math.acospi` for arguments close to 1 +on platforms that do not provide ``acospi()`` in libm. diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 64e5372d73d2f2..eaa1850b8aee1a 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -220,6 +220,12 @@ static const double logpi = 1.144729885849400174143427351353058711647; static double m_acospi(double x) { + if (x >= 0.5) { + /* acos(x) = 2*asin(sqrt((1 - x)/2)). 1 - x is exact here. + Some libms (old fdlibm derivatives) lose precision in acos(x) + near x = 1, while asin() is accurate for small arguments. */ + return 2.0*asin(sqrt((1.0 - x)/2.0))/pi; + } double r = acos(x)/pi; if (isgreater(r, 1.0)) { return 1.0;