xref: /netbsd-src/lib/libm/src/e_acoshl.c (revision 345cf9fb81bd0411c53e25d62cd93bdcaa865312)
1 /* from: FreeBSD: head/lib/msun/src/e_acosh.c 176451 2008-02-22 02:30:36Z das */
2 
3 /*
4  * ====================================================
5  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
6  *
7  * Developed at SunSoft, 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 #include <sys/cdefs.h>
16 
17 #include "namespace.h"
18 
19 #include <float.h>
20 #include <machine/ieee.h>
21 
22 #include "math.h"
23 #include "math_private.h"
24 
25 __weak_alias(acoshl, _acoshl)
26 
27 #ifdef __HAVE_LONG_DOUBLE
28 
29 /*
30  * See e_acosh.c for complete comments.
31  *
32  * Converted to long double by David Schultz <das@FreeBSD.ORG> and
33  * Bruce D. Evans.
34  */
35 
36 #ifdef __i386__
37 #include <ieeefp.h>
38 #endif
39 
40 /* EXP_LARGE is the threshold above which we use acosh(x) ~= log(2x). */
41 #if LDBL_MANT_DIG == 64
42 #define	EXP_LARGE	34
43 #elif LDBL_MANT_DIG == 113
44 #define	EXP_LARGE	58
45 #else
46 #error "Unsupported long double format"
47 #endif
48 
49 #if LDBL_MAX_EXP != 0x4000
50 /* We also require the usual expsign encoding. */
51 #error "Unsupported long double format"
52 #endif
53 
54 #define	BIAS	(LDBL_MAX_EXP - 1)
55 
56 static const double
57 one	= 1.0;
58 
59 #if LDBL_MANT_DIG == 64
60 static const union ieee_ext_u
61 u_ln2 =  LD80C(0xb17217f7d1cf79ac, -1, 6.93147180559945309417e-1L);
62 #define	ln2	u_ln2.extu_ld
63 #elif LDBL_MANT_DIG == 113
64 static const long double
65 ln2 =  6.93147180559945309417232121458176568e-1L;	/* 0x162e42fefa39ef35793c7673007e6.0p-113 */
66 #else
67 #error "Unsupported long double format"
68 #endif
69 
70 long double
71 acoshl(long double x)
72 {
73 	long double t;
74 	int16_t hx;
75 
76 	ENTERI();
77 	GET_LDBL_EXPSIGN(hx, x);
78 	if (hx < 0x3fff) {		/* x < 1, or misnormal */
79 	    RETURNI((x-x)/(x-x));
80 	} else if (hx >= BIAS + EXP_LARGE) { /* x >= LARGE */
81 	    if (hx >= 0x7fff) {		/* x is inf, NaN or misnormal */
82 	        RETURNI(x+x);
83 	    } else
84 		RETURNI(logl(x)+ln2);	/* acosh(huge)=log(2x), or misnormal */
85 	} else if (hx == 0x3fff && x == 1) {
86 	    RETURNI(0.0);		/* acosh(1) = 0 */
87 	} else if (hx >= 0x4000) {	/* LARGE > x >= 2, or misnormal */
88 	    t=x*x;
89 	    RETURNI(logl(2.0*x-one/(x+sqrtl(t-one))));
90 	} else {			/* 1<x<2 */
91 	    t = x-one;
92 	    RETURNI(log1pl(t+sqrtl(2.0*t+t*t)));
93 	}
94 }
95 #else
96 long double
97 acoshl(long double x)
98 {
99 	return acosh(x);
100 }
101 #endif
102