cpython: 8999d702ac29 (original) (raw)
Mercurial > cpython
changeset 104536:8999d702ac29
Issue #28256: Cleanup _math.c Only define fallback implementations when needed. It avoids producing deadcode when the system provides required math functions. [#28256]
Victor Stinner victor.stinner@gmail.com | |
---|---|
date | Tue, 18 Oct 2016 16:29:27 +0200 |
parents | 69523a2327ec |
children | 3aba5552b976 |
files | Modules/_math.c Modules/_math.h |
diffstat | 2 files changed, 41 insertions(+), 32 deletions(-)[+] [-] Modules/_math.c 49 Modules/_math.h 24 |
line wrap: on
line diff
--- a/Modules/_math.c +++ b/Modules/_math.c @@ -19,13 +19,19 @@
+#if !defined(HAVE_ACOSH) || !defined(HAVE_ASINH) static const double ln2 = 6.93147180559945286227E-01; +static const double two_pow_p28 = 268435456.0; /* 228 / +#endif +#if !defined(HAVE_ASINH) || !defined(HAVE_ATANH) static const double two_pow_m28 = 3.7252902984619141E-09; / 2-28 / -static const double two_pow_p28 = 268435456.0; / 2**28 / -#ifndef Py_NAN +#endif +#if !defined(HAVE_ATANH) && !defined(Py_NAN) static const double zero = 0.0; #endif + +#ifndef HAVE_ACOSH / acosh(x)
@@ -59,23 +65,25 @@ double return x+x; } else {
return log(x)+ln2; /* acosh(huge)=log(2x) */[](#l1.29)
} else if (x == 1.) { return 0.0; /* acosh(1) = 0 / } else if (x > 2.) { / 2 < x < 2**28 */return log(x) + ln2; /* acosh(huge)=log(2x) */[](#l1.30) }[](#l1.31)
double t = x*x;[](#l1.37)
return log(2.0*x - 1.0 / (x + sqrt(t - 1.0)));[](#l1.38)
double t = x * x;[](#l1.39)
} else { /* 1 < x <= 2 */ double t = x - 1.0;return log(2.0 * x - 1.0 / (x + sqrt(t - 1.0)));[](#l1.40)
return m_log1p(t + sqrt(2.0*t + t*t));[](#l1.44)
} } +#endif /* HAVE_ACOSH / +#ifndef HAVE_ASINH / asinh(x)return m_log1p(t + sqrt(2.0 * t + t * t));[](#l1.45)
@@ -100,10 +108,10 @@ double return x; /* return x inexact except 0 / } if (absx > two_pow_p28) { / |x| > 2**28 */
w = log(absx)+ln2;[](#l1.59)
w = log(2.0*absx + 1.0 / (sqrt(x*x + 1.0) + absx));[](#l1.63)
} else { /* 2**-28 <= |x| < 2= / double t = xx;w = log(2.0 * absx + 1.0 / (sqrt(x * x + 1.0) + absx));[](#l1.64)
@@ -112,7 +120,10 @@ double return copysign(w, x); } +#endif /* HAVE_ASINH / + +#ifndef HAVE_ATANH / atanh(x)
@@ -145,7 +156,7 @@ double #ifdef Py_NAN return Py_NAN; #else
return x/zero;[](#l1.83)
return x / zero;[](#l1.84)
#endif } if (absx < two_pow_m28) { /* |x| < 2**-28 / @@ -160,7 +171,10 @@ double } return copysign(t, x); } +#endif / HAVE_ATANH / + +#ifndef HAVE_EXPM1 / Mathematically, expm1(x) = exp(x) - 1. The expm1 function is designed to avoid the significant loss of precision that arises from direct evaluation of the expression exp(x) - 1, for x near 0. / @@ -186,16 +200,17 @@ double else return exp(x) - 1.0; } +#endif / HAVE_EXPM1 / + / 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 small. / -#ifdef HAVE_LOG1P - double _Py_log1p(double x) { +#ifdef HAVE_LOG1P / 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. @@ -208,13 +223,7 @@ double else { return log1p(x); } -} - #else - -double -_Py_log1p(double x) -{ /* For x small, we use the following approach. Let y be the nearest float to 1+x, then @@ -236,7 +245,7 @@ double */ double y;
- if (fabs(x) < DBL_EPSILON / 2.) { return x; } else if (-0.5 <= x && x <= 1.) { @@ -246,12 +255,12 @@ double happens, then results from log1p will be inaccurate for small x. */ y = 1.+x;
return log(y)-((y-1.)-x)/y;[](#l1.146)
} else { /* NaNs and infinities should end up here / return log(1.+x); } +#endif / ifdef HAVE_LOG1P / } -#endif / ifdef HAVE_LOG1P */return log(y) - ((y - 1.) - x) / y;[](#l1.147)
--- a/Modules/_math.h +++ b/Modules/_math.h @@ -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 -#define m_acosh acosh +# define m_acosh acosh #else /* if the system doesn't have acosh, use the substitute function defined in Modules/_math.c. / -#define m_acosh _Py_acosh +double _Py_acosh(double x); +# define m_acosh _Py_acosh #endif #ifdef HAVE_ASINH -#define m_asinh asinh +# define m_asinh asinh #else / if the system doesn't have asinh, use the substitute function defined in Modules/_math.c. / -#define m_asinh _Py_asinh +double _Py_asinh(double x); +# define m_asinh _Py_asinh #endif #ifdef HAVE_ATANH -#define m_atanh atanh +# define m_atanh atanh #else / if the system doesn't have atanh, use the substitute function defined in Modules/_math.c. / +double _Py_atanh(double x); #define m_atanh _Py_atanh #endif #ifdef HAVE_EXPM1 -#define m_expm1 expm1 +# define m_expm1 expm1 #else / if the system doesn't have expm1, use the substitute function defined in Modules/_math.c. / +double _Py_expm1(double x); #define m_expm1 _Py_expm1 #endif +double _Py_log1p(double x); + / Use the substitute from _math.c on all platforms: it includes workarounds for buggy handling of zeros. */ #define m_log1p _Py_log1p