Skip to content

Commit 97553fd

Browse files
serhiy-storchakamdickinson
authored andcommitted
bpo-26121: Use C library implementation for math functions: (python#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.
1 parent c5d3bfe commit 97553fd

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed

Doc/whatsnew/3.7.rst

+5
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ Optimizations
133133
in method calls being faster up to 20%.
134134
(Contributed by Yury Selivanov and INADA Naoki in :issue:`26110`.)
135135

136+
* Fast implementation from standard C library is now used for functions
137+
:func:`~math.tgamma`, :func:`~math.lgamma`, :func:`~math.erf` and
138+
:func:`~math.erfc` in the :mod:`math` module.
139+
(Contributed by Serhiy Storchaka in :issue:`26121`.)
140+
136141

137142
Build and C API Changes
138143
=======================

Misc/NEWS

+3
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,9 @@ Extension Modules
270270
Library
271271
-------
272272

273+
- bpo-26121: Use C library implementation for math functions:
274+
tgamma(), lgamma(), erf() and erfc().
275+
273276
- bpo-29619: os.stat() and os.DirEntry.inode() now convert inode (st_ino) using
274277
unsigned integers.
275278

Modules/mathmodule.c

+45-1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,17 @@ static const double pi = 3.141592653589793238462643383279502884197;
7474
static const double sqrtpi = 1.772453850905516027298167483341145182798;
7575
static const double logpi = 1.144729885849400174143427351353058711647;
7676

77+
#ifndef __APPLE__
78+
# ifdef HAVE_TGAMMA
79+
# define USE_TGAMMA
80+
# endif
81+
# ifdef HAVE_LGAMMA
82+
# define USE_LGAMMA
83+
# endif
84+
#endif
85+
86+
#if !defined(USE_TGAMMA) || !defined(USE_LGAMMA)
87+
7788
static double
7889
sinpi(double x)
7990
{
@@ -230,6 +241,7 @@ lanczos_sum(double x)
230241
}
231242
return num/den;
232243
}
244+
#endif /* !defined(USE_TGAMMA) || !defined(USE_LGAMMA) */
233245

234246
/* Constant for +infinity, generated in the same way as float('inf'). */
235247

@@ -263,6 +275,14 @@ m_nan(void)
263275
static double
264276
m_tgamma(double x)
265277
{
278+
#ifdef USE_TGAMMA
279+
if (x == 0.0) {
280+
errno = EDOM;
281+
/* tgamma(+-0.0) = +-inf, divide-by-zero */
282+
return copysign(Py_HUGE_VAL, x);
283+
}
284+
return tgamma(x);
285+
#else
266286
double absx, r, y, z, sqrtpow;
267287

268288
/* special cases */
@@ -354,6 +374,7 @@ m_tgamma(double x)
354374
if (Py_IS_INFINITY(r))
355375
errno = ERANGE;
356376
return r;
377+
#endif
357378
}
358379

359380
/*
@@ -364,7 +385,17 @@ m_tgamma(double x)
364385
static double
365386
m_lgamma(double x)
366387
{
367-
double r, absx;
388+
double r;
389+
390+
#ifdef USE_LGAMMA
391+
r = lgamma(x);
392+
if (errno == ERANGE && x == floor(x) && x <= 0.0) {
393+
errno = EDOM; /* lgamma(n) = inf, divide-by-zero for */
394+
return Py_HUGE_VAL; /* integers n <= 0 */
395+
}
396+
return r;
397+
#else
398+
double absx;
368399

369400
/* special cases */
370401
if (!Py_IS_FINITE(x)) {
@@ -402,8 +433,11 @@ m_lgamma(double x)
402433
if (Py_IS_INFINITY(r))
403434
errno = ERANGE;
404435
return r;
436+
#endif
405437
}
406438

439+
#if !defined(HAVE_ERF) || !defined(HAVE_ERFC)
440+
407441
/*
408442
Implementations of the error function erf(x) and the complementary error
409443
function erfc(x).
@@ -513,11 +547,16 @@ m_erfc_contfrac(double x)
513547
return result;
514548
}
515549

550+
#endif /* !defined(HAVE_ERF) || !defined(HAVE_ERFC) */
551+
516552
/* Error function erf(x), for general x */
517553

518554
static double
519555
m_erf(double x)
520556
{
557+
#ifdef HAVE_ERF
558+
return erf(x);
559+
#else
521560
double absx, cf;
522561

523562
if (Py_IS_NAN(x))
@@ -529,13 +568,17 @@ m_erf(double x)
529568
cf = m_erfc_contfrac(absx);
530569
return x > 0.0 ? 1.0 - cf : cf - 1.0;
531570
}
571+
#endif
532572
}
533573

534574
/* Complementary error function erfc(x), for general x. */
535575

536576
static double
537577
m_erfc(double x)
538578
{
579+
#ifdef HAVE_ERFC
580+
return erfc(x);
581+
#else
539582
double absx, cf;
540583

541584
if (Py_IS_NAN(x))
@@ -547,6 +590,7 @@ m_erfc(double x)
547590
cf = m_erfc_contfrac(absx);
548591
return x > 0.0 ? cf : 2.0 - cf;
549592
}
593+
#endif
550594
}
551595

552596
/*

0 commit comments

Comments
 (0)