OSDN Git Service

libm: fix C99_MATH on __NO_LONG_DOUBLE_MATH hosts
[uclinux-h8/uClibc.git] / libm / s_tanh.c
1 /*
2  * ====================================================
3  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
4  *
5  * Developed at SunPro, a Sun Microsystems, Inc. business.
6  * Permission to use, copy, modify, and distribute this
7  * software is freely granted, provided that this notice
8  * is preserved.
9  * ====================================================
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**-55 : tanh(x) := x*(one+x)
23  *                                              -t
24  *          2**-55 <  x <=  1     : tanh(x) := -----; t = expm1(-2x)
25  *                                             t + 2
26  *                                                   2
27  *          1      <= x <=  22.0  : tanh(x) := 1-  ----- ; t=expm1(2x)
28  *                                                 t + 2
29  *          22.0   <  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 "math.h"
37 #include "math_private.h"
38
39 static const double one=1.0, two=2.0, tiny = 1.0e-300;
40
41 double tanh(double x)
42 {
43         double t,z;
44         int32_t jx,ix;
45
46     /* High word of |x|. */
47         GET_HIGH_WORD(jx,x);
48         ix = jx&0x7fffffff;
49
50     /* x is INF or NaN */
51         if(ix>=0x7ff00000) {
52             if (jx>=0) return one/x+one;    /* tanh(+-inf)=+-1 */
53             else       return one/x-one;    /* tanh(NaN) = NaN */
54         }
55
56     /* |x| < 22 */
57         if (ix < 0x40360000) {          /* |x|<22 */
58             if (ix<0x3c800000)          /* |x|<2**-55 */
59                 return x*(one+x);       /* tanh(small) = small */
60             if (ix>=0x3ff00000) {       /* |x|>=1  */
61                 t = expm1(two*fabs(x));
62                 z = one - two/(t+two);
63             } else {
64                 t = expm1(-two*fabs(x));
65                 z= -t/(t+two);
66             }
67     /* |x| > 22, return +-1 */
68         } else {
69             z = one - tiny;             /* raised inexact flag */
70         }
71         return (jx>=0)? z: -z;
72 }
73 libm_hidden_def(tanh)