* software is freely granted, provided that this notice * is preserved. * ==================================================== */ static const double ln2 = 6.93147180559945286227E-01; static const double huge = 1E+300; static const double two_pow_m28 = 3.7252902984619141E-09; /* 2**-28 */ static const double two_pow_p28 = 268435456.0; /* 2**28 */ static const double zero = 0.0; /* asinh(x) * Method : * Based on * asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ] * we have * asinh(x) := x if 1+x*x=1, * := sign(x)*(log(x)+ln2)) for large |x|, else * := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else * := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2))) */ #ifndef HAVE_ASINH double asinh(double x) { double w; double absx = fabs(x); if (Py_IS_NAN(x) || Py_IS_INFINITY(x)) { return x+x; } if (absx < two_pow_m28) { /* |x| < 2**-28 */ if ((huge + x) > 1.0) return x; /* return x inexact except 0 */ } if (absx > two_pow_p28) { /* |x| > 2**28 */ w = log(absx)+ln2; } else if (absx > 2.0) { /* 2 < |x| < 2**28 */ w = log(2.0*absx + 1.0 / (sqrt(x*x + 1.0) + absx)); } else { /* 2**-28 <= |x| < 2= */ double t = x*x; w = log1p(absx + t / (1.0 + sqrt(1.0 + t))); } return copysign(w, x); } #endif /* HAVE_ASINH */ /* acosh(x) * Method : * Based on * acosh(x) = log [ x + sqrt(x*x-1) ] * we have * acosh(x) := log(x)+ln2, if x is large; else * acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else * acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1. * * Special cases: * acosh(x) is NaN with signal if x<1. * acosh(NaN) is NaN without signal. */ #ifndef HAVE_ACOSH double acosh(double x) { if (Py_IS_NAN(x)) { return x+x; } if (x < 1.) { /* x < 1; return a NaN */ return (x-x)/(x-x); } else if (x >= two_pow_p28) { /* x > 2**28 */ if (Py_IS_INFINITY(x)) { return x+x; } else { return log(x)+ln2; /* acosh(huge)=log(2x) */ } } else if (x == 1.) { return 0.0; /* acosh(1) = 0 */ } else if (x > 2.) { /* 2 < x < 2**28 */ double t = x*x; return log(2.0*x - 1.0 / (x + sqrt(t - 1.0))); } else { /* 1 < x <= 2 */ double t = x - 1.0; return log1p(t + sqrt(2.0*t + t*t)); } } #endif /* HAVE_ACOSH */ /* atanh(x) * Method : * 1.Reduced x to positive by atanh(-x) = -atanh(x) * 2.For x>=0.5 * 1 2x x * atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------) * 2 1 - x 1 - x * * For x<0.5 * atanh(x) = 0.5*log1p(2x+2x*x/(1-x)) * * Special cases: * atanh(x) is NaN if |x| > 1 with signal; * atanh(NaN) is that NaN with no signal; * [atanh(+-1) is +-INF with signal.] * Python: atanh(+-1) raises a ValueError * */ #ifndef HAVE_ATANH double atanh(double x) { double absx; double t; if (Py_IS_NAN(x)) { return x+x; } absx = fabs(x); if (absx == 1.) { return x/zero; } if (absx > 1.) { /* XXX |x| >= 1 */ return (x-x)/(x-x); } if (absx < two_pow_m28) { /* |x| < 2**-28 */ return x; } if (absx < 0.5) { /* |x| < 0.5 */ t = absx+absx; t = 0.5 * log1p(t + t*absx / (1.0 - absx)); } else { /* 0.5 <= |x| <= 1.0 */ t = 0.5 * log1p((absx + absx) / (1.0 - absx)); } return copysign(t, x); } #endif /* HAVE_ATANH */