initial commit
[libm] / src / math / tanh.c
1 /* origin: FreeBSD /usr/src/lib/msun/src/s_tanh.c */
2 /*
3  * ====================================================
4  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
5  *
6  * Developed at SunPro, a Sun Microsystems, Inc. business.
7  * Permission to use, copy, modify, and distribute this
8  * software is freely granted, provided that this notice
9  * is preserved.
10  * ====================================================
11  */
12 /* Tanh(x)
13  * Return the Hyperbolic Tangent of x
14  *
15  * Method :
16  *                                     x    -x
17  *                                    e  - e
18  *      0. tanh(x) is defined to be -----------
19  *                                     x    -x
20  *                                    e  + e
21  *      1. reduce x to non-negative by tanh(-x) = -tanh(x).
22  *      2.  0      <= x <  2**-28 : tanh(x) := x with inexact if x != 0
23  *                                              -t
24  *          2**-28 <= x <  1      : tanh(x) := -----; t = expm1(-2x)
25  *                                             t + 2
26  *                                                   2
27  *          1      <= x <  22     : tanh(x) := 1 - -----; t = expm1(2x)
28  *                                                 t + 2
29  *          22     <= x <= INF    : tanh(x) := 1.
30  *
31  * Special cases:
32  *      tanh(NaN) is NaN;
33  *      only tanh(0)=0 is exact for finite argument.
34  */
35
36 #include "libm.h"
37
38 static const double one = 1.0, two = 2.0, tiny = 1.0e-300, huge = 1.0e300;
39
40 double tanh(double x)
41 {
42         double t,z;
43         int32_t jx,ix;
44
45         GET_HIGH_WORD(jx, x);
46         ix = jx & 0x7fffffff;
47
48         /* x is INF or NaN */
49         if (ix >= 0x7ff00000) {
50                 if (jx >= 0)
51                         return one/x + one;  /* tanh(+-inf)=+-1 */
52                 else
53                         return one/x - one;  /* tanh(NaN) = NaN */
54         }
55
56         if (ix < 0x40360000) {  /* |x| < 22 */
57                 if (ix < 0x3e300000) {  /* |x| < 2**-28 */
58                         /* tanh(tiny) = tiny with inexact */
59                         if (huge+x > one)
60                                 return x;
61                 }
62                 if (ix >= 0x3ff00000) {  /* |x| >= 1  */
63                         t = expm1(two*fabs(x));
64                         z = one - two/(t+two);
65                 } else {
66                         t = expm1(-two*fabs(x));
67                         z= -t/(t+two);
68                 }
69         } else {  /* |x| >= 22, return +-1 */
70                 z = one - tiny;  /* raise inexact */
71         }
72         return jx >= 0 ? z : -z;
73 }