Commit 97553fdf authored by Serhiy Storchaka's avatar Serhiy Storchaka Committed by Mark Dickinson

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.
parent c5d3bfea
...@@ -133,6 +133,11 @@ Optimizations ...@@ -133,6 +133,11 @@ Optimizations
in method calls being faster up to 20%. in method calls being faster up to 20%.
(Contributed by Yury Selivanov and INADA Naoki in :issue:`26110`.) (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 Build and C API Changes
======================= =======================
......
...@@ -270,6 +270,9 @@ Extension Modules ...@@ -270,6 +270,9 @@ Extension Modules
Library 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 - bpo-29619: os.stat() and os.DirEntry.inode() now convert inode (st_ino) using
unsigned integers. unsigned integers.
......
...@@ -74,6 +74,17 @@ static const double pi = 3.141592653589793238462643383279502884197; ...@@ -74,6 +74,17 @@ static const double pi = 3.141592653589793238462643383279502884197;
static const double sqrtpi = 1.772453850905516027298167483341145182798; static const double sqrtpi = 1.772453850905516027298167483341145182798;
static const double logpi = 1.144729885849400174143427351353058711647; 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 static double
sinpi(double x) sinpi(double x)
{ {
...@@ -230,6 +241,7 @@ lanczos_sum(double x) ...@@ -230,6 +241,7 @@ lanczos_sum(double x)
} }
return num/den; return num/den;
} }
#endif /* !defined(USE_TGAMMA) || !defined(USE_LGAMMA) */
/* Constant for +infinity, generated in the same way as float('inf'). */ /* Constant for +infinity, generated in the same way as float('inf'). */
...@@ -263,6 +275,14 @@ m_nan(void) ...@@ -263,6 +275,14 @@ m_nan(void)
static double static double
m_tgamma(double x) 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; double absx, r, y, z, sqrtpow;
/* special cases */ /* special cases */
...@@ -354,6 +374,7 @@ m_tgamma(double x) ...@@ -354,6 +374,7 @@ m_tgamma(double x)
if (Py_IS_INFINITY(r)) if (Py_IS_INFINITY(r))
errno = ERANGE; errno = ERANGE;
return r; return r;
#endif
} }
/* /*
...@@ -364,7 +385,17 @@ m_tgamma(double x) ...@@ -364,7 +385,17 @@ m_tgamma(double x)
static double static double
m_lgamma(double x) 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 */ /* special cases */
if (!Py_IS_FINITE(x)) { if (!Py_IS_FINITE(x)) {
...@@ -402,8 +433,11 @@ m_lgamma(double x) ...@@ -402,8 +433,11 @@ m_lgamma(double x)
if (Py_IS_INFINITY(r)) if (Py_IS_INFINITY(r))
errno = ERANGE; errno = ERANGE;
return r; return r;
#endif
} }
#if !defined(HAVE_ERF) || !defined(HAVE_ERFC)
/* /*
Implementations of the error function erf(x) and the complementary error Implementations of the error function erf(x) and the complementary error
function erfc(x). function erfc(x).
...@@ -513,11 +547,16 @@ m_erfc_contfrac(double x) ...@@ -513,11 +547,16 @@ m_erfc_contfrac(double x)
return result; return result;
} }
#endif /* !defined(HAVE_ERF) || !defined(HAVE_ERFC) */
/* Error function erf(x), for general x */ /* Error function erf(x), for general x */
static double static double
m_erf(double x) m_erf(double x)
{ {
#ifdef HAVE_ERF
return erf(x);
#else
double absx, cf; double absx, cf;
if (Py_IS_NAN(x)) if (Py_IS_NAN(x))
...@@ -529,6 +568,7 @@ m_erf(double x) ...@@ -529,6 +568,7 @@ m_erf(double x)
cf = m_erfc_contfrac(absx); cf = m_erfc_contfrac(absx);
return x > 0.0 ? 1.0 - cf : cf - 1.0; return x > 0.0 ? 1.0 - cf : cf - 1.0;
} }
#endif
} }
/* Complementary error function erfc(x), for general x. */ /* Complementary error function erfc(x), for general x. */
...@@ -536,6 +576,9 @@ m_erf(double x) ...@@ -536,6 +576,9 @@ m_erf(double x)
static double static double
m_erfc(double x) m_erfc(double x)
{ {
#ifdef HAVE_ERFC
return erfc(x);
#else
double absx, cf; double absx, cf;
if (Py_IS_NAN(x)) if (Py_IS_NAN(x))
...@@ -547,6 +590,7 @@ m_erfc(double x) ...@@ -547,6 +590,7 @@ m_erfc(double x)
cf = m_erfc_contfrac(absx); cf = m_erfc_contfrac(absx);
return x > 0.0 ? cf : 2.0 - cf; return x > 0.0 ? cf : 2.0 - cf;
} }
#endif
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment