1 
2 /* @(#)s_asinh.c 5.1 93/09/24 */
3 /*
4  * ====================================================
5  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
6  *
7  * Developed at SunPro, a Sun Microsystems, Inc. business.
8  * Permission to use, copy, modify, and distribute this
9  * software is freely granted, provided that this notice
10  * is preserved.
11  * ====================================================
12  */
13 
14 /*
15 FUNCTION
16 	<<asinh>>, <<asinhf>>---inverse hyperbolic sine
17 
18 INDEX
19 	asinh
20 INDEX
21 	asinhf
22 
23 SYNOPSIS
24 	#include <math.h>
25 	double asinh(double <[x]>);
26 	float asinhf(float <[x]>);
27 
28 DESCRIPTION
29 <<asinh>> calculates the inverse hyperbolic sine of <[x]>.
30 <<asinh>> is defined as
31 @ifnottex
32 . sgn(<[x]>) * log(abs(<[x]>) + sqrt(1+<[x]>*<[x]>))
33 @end ifnottex
34 @tex
35 $$sign(x) \times ln\Bigl(|x| + \sqrt{1+x^2}\Bigr)$$
36 @end tex
37 
38 <<asinhf>> is identical, other than taking and returning floats.
39 
40 RETURNS
41 <<asinh>> and <<asinhf>> return the calculated value.
42 
43 PORTABILITY
44 Neither <<asinh>> nor <<asinhf>> are ANSI C.
45 
46 */
47 
48 /* asinh(x)
49  * Method :
50  *	Based on
51  *		asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
52  *	we have
53  *	asinh(x) := x  if  1+x*x=1,
54  *		 := sign(x)*(log(x)+ln2)) for large |x|, else
55  *		 := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
56  *		 := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
57  */
58 
59 #include "fdlibm.h"
60 
61 #ifdef _NEED_FLOAT64
62 
63 static const __float64
64     one = _F_64(1.00000000000000000000e+00), /* 0x3FF00000, 0x00000000 */
65     ln2 = _F_64(6.93147180559945286227e-01), /* 0x3FE62E42, 0xFEFA39EF */
66     huge = _F_64(1.00000000000000000000e+300);
67 
68 __float64
asinh64(__float64 x)69 asinh64(__float64 x)
70 {
71     __float64 t, w;
72     __int32_t hx, ix;
73     GET_HIGH_WORD(hx, x);
74     ix = hx & 0x7fffffff;
75     if (ix >= 0x7ff00000)
76         return x + x; /* x is inf or NaN */
77     if (ix < 0x3e300000) { /* |x|<2**-28 */
78         if (huge + x > one)
79             return x; /* return x inexact except 0 */
80     }
81     if (ix > 0x41b00000) { /* |x| > 2**28 */
82         w = log64(fabs64(x)) + ln2;
83     } else if (ix > 0x40000000) { /* 2**28 > |x| > 2.0 */
84         t = fabs64(x);
85         w = log64(_F_64(2.0) * t + one / (sqrt64(x * x + one) + t));
86     } else { /* 2.0 > |x| > 2**-28 */
87         t = x * x;
88         w = log1p64(fabs64(x) + t / (one + sqrt64(one + t)));
89     }
90     if (hx > 0)
91         return w;
92     else
93         return -w;
94 }
95 
96 _MATH_ALIAS_d_d(asinh)
97 
98 #endif /* _NEED_FLOAT64 */
99