From 97553fdf9daa8231eb05a1ca9933a2b03b0bdad0 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 11 Mar 2017 23:37:16 +0200 Subject: [PATCH] bpo-26121: Use C library implementation for math functions: (#515) * bpo-26121: Use C library implementation for math functions: tgamma(), lgamma(), erf() and erfc(). * Don't use tgamma() and lgamma() from libc on OS X. --- Doc/whatsnew/3.7.rst | 5 +++++ Misc/NEWS | 3 +++ Modules/mathmodule.c | 46 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 1c737e8c5a..71ae10bbb1 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -133,6 +133,11 @@ Optimizations in method calls being faster up to 20%. (Contributed by Yury Selivanov and INADA Naoki in :issue:`26110`.) +* Fast implementation from standard C library is now used for functions + :func:`~math.tgamma`, :func:`~math.lgamma`, :func:`~math.erf` and + :func:`~math.erfc` in the :mod:`math` module. + (Contributed by Serhiy Storchaka in :issue:`26121`.) + Build and C API Changes ======================= diff --git a/Misc/NEWS b/Misc/NEWS index c4bdbefaa7..59ec700706 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -270,6 +270,9 @@ Extension Modules Library ------- +- bpo-26121: Use C library implementation for math functions: + tgamma(), lgamma(), erf() and erfc(). + - bpo-29619: os.stat() and os.DirEntry.inode() now convert inode (st_ino) using unsigned integers. diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 8bd38d0eb8..bfc028eddd 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -74,6 +74,17 @@ static const double pi = 3.141592653589793238462643383279502884197; static const double sqrtpi = 1.772453850905516027298167483341145182798; static const double logpi = 1.144729885849400174143427351353058711647; +#ifndef __APPLE__ +# ifdef HAVE_TGAMMA +# define USE_TGAMMA +# endif +# ifdef HAVE_LGAMMA +# define USE_LGAMMA +# endif +#endif + +#if !defined(USE_TGAMMA) || !defined(USE_LGAMMA) + static double sinpi(double x) { @@ -230,6 +241,7 @@ lanczos_sum(double x) } return num/den; } +#endif /* !defined(USE_TGAMMA) || !defined(USE_LGAMMA) */ /* Constant for +infinity, generated in the same way as float('inf'). */ @@ -263,6 +275,14 @@ m_nan(void) static double m_tgamma(double x) { +#ifdef USE_TGAMMA + if (x == 0.0) { + errno = EDOM; + /* tgamma(+-0.0) = +-inf, divide-by-zero */ + return copysign(Py_HUGE_VAL, x); + } + return tgamma(x); +#else double absx, r, y, z, sqrtpow; /* special cases */ @@ -354,6 +374,7 @@ m_tgamma(double x) if (Py_IS_INFINITY(r)) errno = ERANGE; return r; +#endif } /* @@ -364,7 +385,17 @@ m_tgamma(double x) static double m_lgamma(double x) { - double r, absx; + double r; + +#ifdef USE_LGAMMA + r = lgamma(x); + if (errno == ERANGE && x == floor(x) && x <= 0.0) { + errno = EDOM; /* lgamma(n) = inf, divide-by-zero for */ + return Py_HUGE_VAL; /* integers n <= 0 */ + } + return r; +#else + double absx; /* special cases */ if (!Py_IS_FINITE(x)) { @@ -402,8 +433,11 @@ m_lgamma(double x) if (Py_IS_INFINITY(r)) errno = ERANGE; return r; +#endif } +#if !defined(HAVE_ERF) || !defined(HAVE_ERFC) + /* Implementations of the error function erf(x) and the complementary error function erfc(x). @@ -513,11 +547,16 @@ m_erfc_contfrac(double x) return result; } +#endif /* !defined(HAVE_ERF) || !defined(HAVE_ERFC) */ + /* Error function erf(x), for general x */ static double m_erf(double x) { +#ifdef HAVE_ERF + return erf(x); +#else double absx, cf; if (Py_IS_NAN(x)) @@ -529,6 +568,7 @@ m_erf(double x) cf = m_erfc_contfrac(absx); return x > 0.0 ? 1.0 - cf : cf - 1.0; } +#endif } /* Complementary error function erfc(x), for general x. */ @@ -536,6 +576,9 @@ m_erf(double x) static double m_erfc(double x) { +#ifdef HAVE_ERFC + return erfc(x); +#else double absx, cf; if (Py_IS_NAN(x)) @@ -547,6 +590,7 @@ m_erfc(double x) cf = m_erfc_contfrac(absx); return x > 0.0 ? cf : 2.0 - cf; } +#endif } /* -- 2.40.0