Issue #28256: Cleanup _math.c

Only define fallback implementations when needed. It avoids producing deadcode
when the system provides required math functions.
This commit is contained in:
Victor Stinner 2016-10-18 16:29:27 +02:00
parent 22e36afc17
commit bf9655854b
2 changed files with 41 additions and 32 deletions

View File

@ -19,13 +19,19 @@
* ==================================================== * ====================================================
*/ */
#if !defined(HAVE_ACOSH) || !defined(HAVE_ASINH)
static const double ln2 = 6.93147180559945286227E-01; static const double ln2 = 6.93147180559945286227E-01;
static const double two_pow_m28 = 3.7252902984619141E-09; /* 2**-28 */
static const double two_pow_p28 = 268435456.0; /* 2**28 */ static const double two_pow_p28 = 268435456.0; /* 2**28 */
#ifndef Py_NAN #endif
#if !defined(HAVE_ASINH) || !defined(HAVE_ATANH)
static const double two_pow_m28 = 3.7252902984619141E-09; /* 2**-28 */
#endif
#if !defined(HAVE_ATANH) && !defined(Py_NAN)
static const double zero = 0.0; static const double zero = 0.0;
#endif #endif
#ifndef HAVE_ACOSH
/* acosh(x) /* acosh(x)
* Method : * Method :
* Based on * Based on
@ -59,23 +65,25 @@ _Py_acosh(double x)
return x+x; return x+x;
} }
else { else {
return log(x)+ln2; /* acosh(huge)=log(2x) */ return log(x) + ln2; /* acosh(huge)=log(2x) */
} }
} }
else if (x == 1.) { else if (x == 1.) {
return 0.0; /* acosh(1) = 0 */ return 0.0; /* acosh(1) = 0 */
} }
else if (x > 2.) { /* 2 < x < 2**28 */ else if (x > 2.) { /* 2 < x < 2**28 */
double t = x*x; double t = x * x;
return log(2.0*x - 1.0 / (x + sqrt(t - 1.0))); return log(2.0 * x - 1.0 / (x + sqrt(t - 1.0)));
} }
else { /* 1 < x <= 2 */ else { /* 1 < x <= 2 */
double t = x - 1.0; double t = x - 1.0;
return m_log1p(t + sqrt(2.0*t + t*t)); return m_log1p(t + sqrt(2.0 * t + t * t));
} }
} }
#endif /* HAVE_ACOSH */
#ifndef HAVE_ASINH
/* asinh(x) /* asinh(x)
* Method : * Method :
* Based on * Based on
@ -100,10 +108,10 @@ _Py_asinh(double x)
return x; /* return x inexact except 0 */ return x; /* return x inexact except 0 */
} }
if (absx > two_pow_p28) { /* |x| > 2**28 */ if (absx > two_pow_p28) { /* |x| > 2**28 */
w = log(absx)+ln2; w = log(absx) + ln2;
} }
else if (absx > 2.0) { /* 2 < |x| < 2**28 */ else if (absx > 2.0) { /* 2 < |x| < 2**28 */
w = log(2.0*absx + 1.0 / (sqrt(x*x + 1.0) + absx)); w = log(2.0 * absx + 1.0 / (sqrt(x * x + 1.0) + absx));
} }
else { /* 2**-28 <= |x| < 2= */ else { /* 2**-28 <= |x| < 2= */
double t = x*x; double t = x*x;
@ -112,7 +120,10 @@ _Py_asinh(double x)
return copysign(w, x); return copysign(w, x);
} }
#endif /* HAVE_ASINH */
#ifndef HAVE_ATANH
/* atanh(x) /* atanh(x)
* Method : * Method :
* 1.Reduced x to positive by atanh(-x) = -atanh(x) * 1.Reduced x to positive by atanh(-x) = -atanh(x)
@ -145,7 +156,7 @@ _Py_atanh(double x)
#ifdef Py_NAN #ifdef Py_NAN
return Py_NAN; return Py_NAN;
#else #else
return x/zero; return x / zero;
#endif #endif
} }
if (absx < two_pow_m28) { /* |x| < 2**-28 */ if (absx < two_pow_m28) { /* |x| < 2**-28 */
@ -160,7 +171,10 @@ _Py_atanh(double x)
} }
return copysign(t, x); return copysign(t, x);
} }
#endif /* HAVE_ATANH */
#ifndef HAVE_EXPM1
/* Mathematically, expm1(x) = exp(x) - 1. The expm1 function is designed /* Mathematically, expm1(x) = exp(x) - 1. The expm1 function is designed
to avoid the significant loss of precision that arises from direct to avoid the significant loss of precision that arises from direct
evaluation of the expression exp(x) - 1, for x near 0. */ evaluation of the expression exp(x) - 1, for x near 0. */
@ -186,16 +200,17 @@ _Py_expm1(double x)
else else
return exp(x) - 1.0; return exp(x) - 1.0;
} }
#endif /* HAVE_EXPM1 */
/* log1p(x) = log(1+x). The log1p function is designed to avoid the /* log1p(x) = log(1+x). The log1p function is designed to avoid the
significant loss of precision that arises from direct evaluation when x is significant loss of precision that arises from direct evaluation when x is
small. */ small. */
#ifdef HAVE_LOG1P
double double
_Py_log1p(double x) _Py_log1p(double x)
{ {
#ifdef HAVE_LOG1P
/* Some platforms supply a log1p function but don't respect the sign of /* Some platforms supply a log1p function but don't respect the sign of
zero: log1p(-0.0) gives 0.0 instead of the correct result of -0.0. zero: log1p(-0.0) gives 0.0 instead of the correct result of -0.0.
@ -208,13 +223,7 @@ _Py_log1p(double x)
else { else {
return log1p(x); return log1p(x);
} }
}
#else #else
double
_Py_log1p(double x)
{
/* For x small, we use the following approach. Let y be the nearest float /* For x small, we use the following approach. Let y be the nearest float
to 1+x, then to 1+x, then
@ -236,7 +245,7 @@ _Py_log1p(double x)
*/ */
double y; double y;
if (fabs(x) < DBL_EPSILON/2.) { if (fabs(x) < DBL_EPSILON / 2.) {
return x; return x;
} }
else if (-0.5 <= x && x <= 1.) { else if (-0.5 <= x && x <= 1.) {
@ -246,12 +255,12 @@ _Py_log1p(double x)
happens, then results from log1p will be inaccurate happens, then results from log1p will be inaccurate
for small x. */ for small x. */
y = 1.+x; y = 1.+x;
return log(y)-((y-1.)-x)/y; return log(y) - ((y - 1.) - x) / y;
} }
else { else {
/* NaNs and infinities should end up here */ /* NaNs and infinities should end up here */
return log(1.+x); return log(1.+x);
} }
#endif /* ifdef HAVE_LOG1P */
} }
#endif /* ifdef HAVE_LOG1P */

View File

@ -1,41 +1,41 @@
double _Py_acosh(double x);
double _Py_asinh(double x);
double _Py_atanh(double x);
double _Py_expm1(double x);
double _Py_log1p(double x);
#ifdef HAVE_ACOSH #ifdef HAVE_ACOSH
#define m_acosh acosh # define m_acosh acosh
#else #else
/* if the system doesn't have acosh, use the substitute /* if the system doesn't have acosh, use the substitute
function defined in Modules/_math.c. */ function defined in Modules/_math.c. */
#define m_acosh _Py_acosh double _Py_acosh(double x);
# define m_acosh _Py_acosh
#endif #endif
#ifdef HAVE_ASINH #ifdef HAVE_ASINH
#define m_asinh asinh # define m_asinh asinh
#else #else
/* if the system doesn't have asinh, use the substitute /* if the system doesn't have asinh, use the substitute
function defined in Modules/_math.c. */ function defined in Modules/_math.c. */
#define m_asinh _Py_asinh double _Py_asinh(double x);
# define m_asinh _Py_asinh
#endif #endif
#ifdef HAVE_ATANH #ifdef HAVE_ATANH
#define m_atanh atanh # define m_atanh atanh
#else #else
/* if the system doesn't have atanh, use the substitute /* if the system doesn't have atanh, use the substitute
function defined in Modules/_math.c. */ function defined in Modules/_math.c. */
double _Py_atanh(double x);
#define m_atanh _Py_atanh #define m_atanh _Py_atanh
#endif #endif
#ifdef HAVE_EXPM1 #ifdef HAVE_EXPM1
#define m_expm1 expm1 # define m_expm1 expm1
#else #else
/* if the system doesn't have expm1, use the substitute /* if the system doesn't have expm1, use the substitute
function defined in Modules/_math.c. */ function defined in Modules/_math.c. */
double _Py_expm1(double x);
#define m_expm1 _Py_expm1 #define m_expm1 _Py_expm1
#endif #endif
double _Py_log1p(double x);
/* Use the substitute from _math.c on all platforms: /* Use the substitute from _math.c on all platforms:
it includes workarounds for buggy handling of zeros. */ it includes workarounds for buggy handling of zeros. */
#define m_log1p _Py_log1p #define m_log1p _Py_log1p