1 /*-
2 * Copyright (c) 2014-2018 Carsten Sonne Larsen <cs@innolan.net>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * Project homepage:
26 * https://amath.innolan.net
27 *
28 * The original source code can be obtained from:
29 * http://www.netlib.org/fdlibm/e_sinh.c
30 *
31 * =================================================================
32 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
33 *
34 * Developed at SunSoft, a Sun Microsystems, Inc. business.
35 * Permission to use, copy, modify, and distribute this
36 * software is freely granted, provided that this notice
37 * is preserved.
38 * =================================================================
39 */
40
41 /**
42 * @file sinh.c
43 * @brief Hyperbolic sine function
44 */
45
46 #include "prim.h"
47
48 #if __GNUC__ > 2
49 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
50 #endif
51
52 static const double
53 one = 1.0,
54 shuge = 1.0e307;
55
56 /**
57 * @brief Hyperbolic sine function
58 * @details
59 * <pre>
60 * Method
61 * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
62 * 1. Replace x by |x| (sinh(-x) = -sinh(x)).
63 * 2.
64 * E + E/(E+1)
65 * 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x)
66 * 2
67 *
68 * 22 <= x <= lnovft : sinh(x) := exp(x)/2
69 * lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2)
70 * ln2ovft < x : sinh(x) := x*shuge (overflow)
71 *
72 * Special cases
73 * sinh(x) is |x| if x is +INF, -INF, or NaN.
74 * only sinh(0)=0 is exact for finite x.
75 * </pre>
76 */
sinh(double x)77 double sinh(double x)
78 {
79 double t, w, h;
80 int32_t ix, jx;
81 uint32_t lx;
82
83 // High word of |x|
84 GET_HIGH_WORD(jx, x);
85 ix = jx & 0x7FFFFFFF;
86
87 // x is INF or NaN
88 if (ix >= 0x7FF00000)
89 {
90 return NAN;
91 }
92
93 h = 0.5;
94 if (jx < 0)
95 h = -h;
96 /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
97 if (ix < 0x40360000)
98 { /* |x|<22 */
99 if (ix < 0x3E300000) /* |x|<2**-28 */
100 if (shuge + x > one)
101 return x; /* sinh(tiny) = tiny with inexact */
102 t = expm1(fabs(x));
103 if (ix < 0x3FF00000)
104 return h * (2.0 * t - t * t / (t + one));
105 return h * (t + t / (t + one));
106 }
107
108 /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
109 if (ix < 0x40862E42)
110 return h * exp(fabs(x));
111
112 /* |x| in [log(maxdouble), overflowthresold] */
113 lx = *((((*(uint32_t *)&one) >> 29)) + (uint32_t *)&x);
114 if (ix < 0x408633CE || ((ix == 0x408633CE) && (lx <= (uint32_t)0X8FB9F87D)))
115 {
116 w = exp(0.5 * fabs(x));
117 t = h * w;
118 return t * w;
119 }
120
121 /* |x| > overflowthresold, sinh(x) overflow */
122 return x * shuge;
123 }
124