1a48e1f22SSteve Kargl /* from: FreeBSD: head/lib/msun/src/s_tanhl.c XXX */
2a48e1f22SSteve Kargl
3a48e1f22SSteve Kargl /*
4a48e1f22SSteve Kargl * ====================================================
5a48e1f22SSteve Kargl * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
6a48e1f22SSteve Kargl *
7a48e1f22SSteve Kargl * Developed at SunPro, a Sun Microsystems, Inc. business.
8a48e1f22SSteve Kargl * Permission to use, copy, modify, and distribute this
9a48e1f22SSteve Kargl * software is freely granted, provided that this notice
10a48e1f22SSteve Kargl * is preserved.
11a48e1f22SSteve Kargl * ====================================================
12a48e1f22SSteve Kargl */
13a48e1f22SSteve Kargl
14a48e1f22SSteve Kargl /*
15a48e1f22SSteve Kargl * See s_tanh.c for complete comments.
16a48e1f22SSteve Kargl *
17a48e1f22SSteve Kargl * Converted to long double by Bruce D. Evans.
18a48e1f22SSteve Kargl */
19a48e1f22SSteve Kargl
20a48e1f22SSteve Kargl #include <float.h>
21a48e1f22SSteve Kargl #ifdef __i386__
22a48e1f22SSteve Kargl #include <ieeefp.h>
23a48e1f22SSteve Kargl #endif
24a48e1f22SSteve Kargl
25a48e1f22SSteve Kargl #include "math.h"
26a48e1f22SSteve Kargl #include "math_private.h"
27a48e1f22SSteve Kargl #include "fpmath.h"
28a48e1f22SSteve Kargl #include "k_expl.h"
29a48e1f22SSteve Kargl
30a48e1f22SSteve Kargl #if LDBL_MAX_EXP != 0x4000
31a48e1f22SSteve Kargl /* We also require the usual expsign encoding. */
32a48e1f22SSteve Kargl #error "Unsupported long double format"
33a48e1f22SSteve Kargl #endif
34a48e1f22SSteve Kargl
35a48e1f22SSteve Kargl #define BIAS (LDBL_MAX_EXP - 1)
36a48e1f22SSteve Kargl
37a48e1f22SSteve Kargl static const volatile double tiny = 1.0e-300;
38a48e1f22SSteve Kargl static const double one = 1.0;
39a48e1f22SSteve Kargl #if LDBL_MANT_DIG == 64
40a48e1f22SSteve Kargl /*
41a48e1f22SSteve Kargl * Domain [-0.25, 0.25], range ~[-1.6304e-22, 1.6304e-22]:
42a48e1f22SSteve Kargl * |tanh(x)/x - t(x)| < 2**-72.3
43a48e1f22SSteve Kargl */
44a48e1f22SSteve Kargl static const union IEEEl2bits
45a48e1f22SSteve Kargl T3u = LD80C(0xaaaaaaaaaaaaaa9f, -2, -3.33333333333333333017e-1L);
46a48e1f22SSteve Kargl #define T3 T3u.e
47a48e1f22SSteve Kargl static const double
48a48e1f22SSteve Kargl T5 = 1.3333333333333314e-1, /* 0x1111111111110a.0p-55 */
49a48e1f22SSteve Kargl T7 = -5.3968253968210485e-2, /* -0x1ba1ba1ba1a1a1.0p-57 */
50a48e1f22SSteve Kargl T9 = 2.1869488531393817e-2, /* 0x1664f488172022.0p-58 */
51a48e1f22SSteve Kargl T11 = -8.8632352345964591e-3, /* -0x1226e34bc138d5.0p-59 */
52a48e1f22SSteve Kargl T13 = 3.5921169709993771e-3, /* 0x1d6d371d3e400f.0p-61 */
53a48e1f22SSteve Kargl T15 = -1.4555786415756001e-3, /* -0x17d923aa63814d.0p-62 */
54a48e1f22SSteve Kargl T17 = 5.8645267876296793e-4, /* 0x13378589b85aa7.0p-63 */
55a48e1f22SSteve Kargl T19 = -2.1121033571392224e-4; /* -0x1baf0af80c4090.0p-65 */
56a48e1f22SSteve Kargl #elif LDBL_MANT_DIG == 113
57a48e1f22SSteve Kargl /*
58a48e1f22SSteve Kargl * Domain [-0.25, 0.25], range ~[-2.4211e-37, 2.4211e-37]:
59a48e1f22SSteve Kargl * |tanh(x)/x - t(x)| < 2**121.6
60a48e1f22SSteve Kargl */
61a48e1f22SSteve Kargl static const long double
62a48e1f22SSteve Kargl T3 = -3.33333333333333333333333333333332980e-1L, /* -0x1555555555555555555555555554e.0p-114L */
63a48e1f22SSteve Kargl T5 = 1.33333333333333333333333333332707260e-1L, /* 0x1111111111111111111111110ab7b.0p-115L */
64a48e1f22SSteve Kargl T7 = -5.39682539682539682539682535723482314e-2L, /* -0x1ba1ba1ba1ba1ba1ba1ba17b5fc98.0p-117L */
65a48e1f22SSteve Kargl T9 = 2.18694885361552028218693591149061717e-2L, /* 0x1664f4882c10f9f32d6b1a12a25e5.0p-118L */
66a48e1f22SSteve Kargl T11 = -8.86323552990219656883762347736381851e-3L, /* -0x1226e355e6c23c8f5a5a0f386cb4d.0p-119L */
67a48e1f22SSteve Kargl T13 = 3.59212803657248101358314398220822722e-3L, /* 0x1d6d3d0e157ddfb403ad3637442c6.0p-121L */
68a48e1f22SSteve Kargl T15 = -1.45583438705131796512568010348874662e-3L; /* -0x17da36452b75e150c44cc34253b34.0p-122L */
69a48e1f22SSteve Kargl static const double
70a48e1f22SSteve Kargl T17 = 5.9002744094556621e-4, /* 0x1355824803668e.0p-63 */
71a48e1f22SSteve Kargl T19 = -2.3912911424260516e-4, /* -0x1f57d7734c8dde.0p-65 */
72a48e1f22SSteve Kargl T21 = 9.6915379535512898e-5, /* 0x1967e18ad6a6ca.0p-66 */
73a48e1f22SSteve Kargl T23 = -3.9278322983156353e-5, /* -0x1497d8e6b75729.0p-67 */
74a48e1f22SSteve Kargl T25 = 1.5918887220143869e-5, /* 0x10b1319998cafa.0p-68 */
75a48e1f22SSteve Kargl T27 = -6.4514295231630956e-6, /* -0x1b0f2b71b218eb.0p-70 */
76a48e1f22SSteve Kargl T29 = 2.6120754043964365e-6, /* 0x15e963a3cf3a39.0p-71 */
77a48e1f22SSteve Kargl T31 = -1.0407567231003314e-6, /* -0x1176041e656869.0p-72 */
78a48e1f22SSteve Kargl T33 = 3.4744117554063574e-7; /* 0x1750fe732cab9c.0p-74 */
79a48e1f22SSteve Kargl #endif /* LDBL_MANT_DIG == 64 */
80a48e1f22SSteve Kargl
81a48e1f22SSteve Kargl static inline long double
divl(long double a,long double b,long double c,long double d,long double e,long double f)82a48e1f22SSteve Kargl divl(long double a, long double b, long double c, long double d,
83a48e1f22SSteve Kargl long double e, long double f)
84a48e1f22SSteve Kargl {
851531aa5fSSteve Kargl long double inv, r;
86a48e1f22SSteve Kargl float fr, fw;
87a48e1f22SSteve Kargl
88a48e1f22SSteve Kargl _2sumF(a, c);
89a48e1f22SSteve Kargl b = b + c;
90a48e1f22SSteve Kargl _2sumF(d, f);
91a48e1f22SSteve Kargl e = e + f;
92a48e1f22SSteve Kargl
93a48e1f22SSteve Kargl inv = 1 / (d + e);
94a48e1f22SSteve Kargl
95a48e1f22SSteve Kargl r = (a + b) * inv;
96a48e1f22SSteve Kargl fr = r;
97a48e1f22SSteve Kargl r = fr;
98a48e1f22SSteve Kargl
99a48e1f22SSteve Kargl fw = d + e;
100a48e1f22SSteve Kargl e = d - fw + e;
101a48e1f22SSteve Kargl d = fw;
102a48e1f22SSteve Kargl
103a48e1f22SSteve Kargl r = r + (a - d * r + b - e * r) * inv;
104a48e1f22SSteve Kargl
105a48e1f22SSteve Kargl return r;
106a48e1f22SSteve Kargl }
107a48e1f22SSteve Kargl
108a48e1f22SSteve Kargl long double
tanhl(long double x)109a48e1f22SSteve Kargl tanhl(long double x)
110a48e1f22SSteve Kargl {
111a48e1f22SSteve Kargl long double hi,lo,s,x2,x4,z;
112*cf825f93SEd Maste #if LDBL_MANT_DIG == 113
113a48e1f22SSteve Kargl double dx2;
114*cf825f93SEd Maste #endif
115a48e1f22SSteve Kargl int16_t jx,ix;
116a48e1f22SSteve Kargl
117a48e1f22SSteve Kargl GET_LDBL_EXPSIGN(jx,x);
118a48e1f22SSteve Kargl ix = jx&0x7fff;
119a48e1f22SSteve Kargl
120a48e1f22SSteve Kargl /* x is INF or NaN */
121a48e1f22SSteve Kargl if(ix>=0x7fff) {
122a48e1f22SSteve Kargl if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */
123a48e1f22SSteve Kargl else return one/x-one; /* tanh(NaN) = NaN */
124a48e1f22SSteve Kargl }
125a48e1f22SSteve Kargl
126a48e1f22SSteve Kargl ENTERI();
127a48e1f22SSteve Kargl
1281531aa5fSSteve Kargl /* |x| < 40 */
1291531aa5fSSteve Kargl if (ix < 0x4004 || fabsl(x) < 40) { /* |x|<40 */
130a48e1f22SSteve Kargl if (__predict_false(ix<BIAS-(LDBL_MANT_DIG+1)/2)) { /* |x|<TINY */
131a48e1f22SSteve Kargl /* tanh(+-0) = +0; tanh(tiny) = tiny(-+) with inexact: */
132a48e1f22SSteve Kargl return (x == 0 ? x : (0x1p200 * x - x) * 0x1p-200);
133a48e1f22SSteve Kargl }
1341531aa5fSSteve Kargl if (ix<0x3ffd) { /* |x|<0.25 */
135a48e1f22SSteve Kargl x2 = x*x;
136a48e1f22SSteve Kargl #if LDBL_MANT_DIG == 64
137a48e1f22SSteve Kargl x4 = x2*x2;
138a48e1f22SSteve Kargl RETURNI(((T19*x2 + T17)*x4 + (T15*x2 + T13))*(x2*x*x2*x4*x4) +
139a48e1f22SSteve Kargl ((T11*x2 + T9)*x4 + (T7*x2 + T5))*(x2*x*x2) +
140a48e1f22SSteve Kargl T3*(x2*x) + x);
141a48e1f22SSteve Kargl #elif LDBL_MANT_DIG == 113
142a48e1f22SSteve Kargl dx2 = x2;
1431531aa5fSSteve Kargl #if 0
144a48e1f22SSteve Kargl RETURNI(((((((((((((((T33*dx2 + T31)*dx2 + T29)*dx2 + T27)*dx2 +
145a48e1f22SSteve Kargl T25)*x2 + T23)*x2 + T21)*x2 + T19)*x2 + T17)*x2 +
146a48e1f22SSteve Kargl T15)*x2 + T13)*x2 + T11)*x2 + T9)*x2 + T7)*x2 + T5)*
147a48e1f22SSteve Kargl (x2*x*x2) +
148a48e1f22SSteve Kargl T3*(x2*x) + x);
1491531aa5fSSteve Kargl #else
1501531aa5fSSteve Kargl long double q = ((((((((((((((T33*dx2 + T31)*dx2 + T29)*dx2 + T27)*dx2 +
1511531aa5fSSteve Kargl T25)*x2 + T23)*x2 + T21)*x2 + T19)*x2 + T17)*x2 +
1521531aa5fSSteve Kargl T15)*x2 + T13)*x2 + T11)*x2 + T9)*x2 + T7)*x2 + T5)*
1531531aa5fSSteve Kargl (x2*x*x2);
1541531aa5fSSteve Kargl RETURNI(q + T3*(x2*x) + x);
1551531aa5fSSteve Kargl #endif
156a48e1f22SSteve Kargl #endif
157a48e1f22SSteve Kargl }
158a48e1f22SSteve Kargl k_hexpl(2*fabsl(x), &hi, &lo);
1591531aa5fSSteve Kargl if (ix<0x4001 && fabsl(x) < 1.5) /* |x|<1.5 */
160a48e1f22SSteve Kargl z = divl(hi, lo, -0.5, hi, lo, 0.5);
161a48e1f22SSteve Kargl else
162a48e1f22SSteve Kargl z = one - one/(lo+0.5+hi);
163a48e1f22SSteve Kargl /* |x| >= 40, return +-1 */
164a48e1f22SSteve Kargl } else {
165a48e1f22SSteve Kargl z = one - tiny; /* raise inexact flag */
166a48e1f22SSteve Kargl }
167a48e1f22SSteve Kargl s = 1;
168a48e1f22SSteve Kargl if (jx<0) s = -1;
169a48e1f22SSteve Kargl RETURNI(s*z);
170a48e1f22SSteve Kargl }
171