xref: /illumos-gate/usr/src/lib/libm/common/Q/coshl.c (revision a6bde1a23b60f140c7ed78df979c2e22b1ed9b2c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
24  */
25 /*
26  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
27  * Use is subject to license terms.
28  */
29 
30 #pragma weak coshl = __coshl
31 
32 #include "libm.h"
33 #include "longdouble.h"
34 
35 
36 /*
37  * coshl(X)
38  * RETURN THE HYPERBOLIC COSINE OF X
39  *
40  * Method :
41  *	1. Replace x by |x| (coshl(x) = coshl(-x)).
42  *	2.
43  *		                                       [ expl(x) - 1 ]^2
44  *	    0        <= x <= 0.3465 : coshl(x) := 1 + -------------------
45  *							    2*expl(x)
46  *
47  *		                                  expl(x) + 1/expl(x)
48  *	    0.3465   <= x <= thresh : coshl(x) := -------------------
49  *							   2
50  *	    thresh   <= x <= lnovft : coshl(x) := expl(x)/2
51  *	    lnovft   <= x <  INF    : coshl(x) := scalbnl(expl(x-1024*ln2),1023)
52  *
53  * here
54  *	thr1		a number that is near one half of ln2.
55  *	thr2		a number such that
56  *				expl(thresh)+expl(-thresh)=expl(thresh)
57  *	lnovft:		logrithm of the overflow threshold
58  *			= MEP1*ln2 chopped to machine precision.
59  *	ME		maximum exponent
60  *	MEP1		maximum exponent plus 1
61  *
62  * Special cases:
63  *	coshl(x) is |x| if x is +INF, -INF, or NaN.
64  *	only coshl(0)=1 is exact for finite x.
65  */
66 
67 #define	ME	16383
68 #define	MEP1	16384
69 #define	LNOVFT	1.135652340629414394949193107797076342845e+4L
70 		/* last 32 bits of LN2HI is zero */
71 #define	LN2HI   6.931471805599453094172319547495844850203e-0001L
72 #define	LN2LO   1.667085920830552208890449330400379754169e-0025L
73 #define	THR1	0.3465L
74 #define	THR2	45.L
75 
76 static const long double
77 	half 	= 0.5L,
78 	tinyl	= 7.5e-37L,
79 	one	= 1.0L,
80 	ln2hi   = LN2HI,
81 	ln2lo   = LN2LO,
82 	lnovftL	= LNOVFT,
83 	thr1	= THR1,
84 	thr2	= THR2;
85 
86 long double
87 coshl(long double x) {
88 	long double t, w;
89 
90 	w = fabsl(x);
91 	if (!finitel(w))
92 		return (w + w);		/* x is INF or NaN */
93 	if (w < thr1) {
94 		t = w < tinyl ? w : expm1l(w);
95 		w = one + t;
96 		if (w != one)
97 			w = one + (t * t) / (w + w);
98 		return (w);
99 	} else if (w < thr2) {
100 		t = expl(w);
101 		return (half * (t + one / t));
102 	} else if (w <= lnovftL)
103 		return (half * expl(w));
104 	else {
105 		return (scalbnl(expl((w - MEP1 * ln2hi) - MEP1 * ln2lo), ME));
106 	}
107 }
108