1181074Sdas
2181074Sdas/* @(#)e_acos.c 1.3 95/01/18 */
3181074Sdas/* FreeBSD: head/lib/msun/src/e_acos.c 176451 2008-02-22 02:30:36Z das */
4181074Sdas/*
5181074Sdas * ====================================================
6181074Sdas * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
7181074Sdas *
8181074Sdas * Developed at SunSoft, a Sun Microsystems, Inc. business.
9181074Sdas * Permission to use, copy, modify, and distribute this
10181074Sdas * software is freely granted, provided that this notice
11181074Sdas * is preserved.
12181074Sdas * ====================================================
13181074Sdas */
14181074Sdas
15181074Sdas#include <sys/cdefs.h>
16181074Sdas__FBSDID("$FreeBSD$");
17181074Sdas
18181074Sdas/*
19181074Sdas * See comments in e_acos.c.
20181074Sdas * Converted to long double by David Schultz <das@FreeBSD.ORG>.
21181074Sdas */
22181074Sdas
23181074Sdas#include <float.h>
24181074Sdas
25181074Sdas#include "invtrig.h"
26181074Sdas#include "math.h"
27181074Sdas#include "math_private.h"
28181074Sdas
29181074Sdasstatic const long double
30181152Sdasone=  1.00000000000000000000e+00;
31181152Sdas
32181152Sdas#ifdef __i386__
33181152Sdas/* XXX Work around the fact that gcc truncates long double constants on i386 */
34181152Sdasstatic volatile double
35181152Sdaspi1 =  3.14159265358979311600e+00,	/*  0x1.921fb54442d18p+1  */
36181152Sdaspi2 =  1.22514845490862001043e-16;	/*  0x1.1a80000000000p-53 */
37181152Sdas#define	pi	((long double)pi1 + pi2)
38181152Sdas#else
39181152Sdasstatic const long double
40181074Sdaspi =  3.14159265358979323846264338327950280e+00L;
41181152Sdas#endif
42181152Sdas
43181074Sdaslong double
44181074Sdasacosl(long double x)
45181074Sdas{
46181074Sdas	union IEEEl2bits u;
47181074Sdas	long double z,p,q,r,w,s,c,df;
48181074Sdas	int16_t expsign, expt;
49181074Sdas	u.e = x;
50181074Sdas	expsign = u.xbits.expsign;
51181074Sdas	expt = expsign & 0x7fff;
52181074Sdas	if(expt >= BIAS) {	/* |x| >= 1 */
53181074Sdas	    if(expt==BIAS && ((u.bits.manh&~LDBL_NBIT)|u.bits.manl)==0) {
54181074Sdas		if (expsign>0) return 0.0;	/* acos(1) = 0  */
55181074Sdas		else return pi+2.0*pio2_lo;	/* acos(-1)= pi */
56181074Sdas	    }
57181074Sdas	    return (x-x)/(x-x);		/* acos(|x|>1) is NaN */
58181074Sdas	}
59181074Sdas	if(expt<BIAS-1) {	/* |x| < 0.5 */
60181074Sdas	    if(expt<ACOS_CONST) return pio2_hi+pio2_lo;/*x tiny: acosl=pi/2*/
61181074Sdas	    z = x*x;
62181074Sdas	    p = P(z);
63181074Sdas	    q = Q(z);
64181074Sdas	    r = p/q;
65181074Sdas	    return pio2_hi - (x - (pio2_lo-x*r));
66181074Sdas	} else  if (expsign<0) {	/* x < -0.5 */
67181074Sdas	    z = (one+x)*0.5;
68181074Sdas	    p = P(z);
69181074Sdas	    q = Q(z);
70181074Sdas	    s = sqrtl(z);
71181074Sdas	    r = p/q;
72181074Sdas	    w = r*s-pio2_lo;
73181074Sdas	    return pi - 2.0*(s+w);
74181074Sdas	} else {			/* x > 0.5 */
75181074Sdas	    z = (one-x)*0.5;
76181074Sdas	    s = sqrtl(z);
77181074Sdas	    u.e = s;
78181074Sdas	    u.bits.manl = 0;
79181074Sdas	    df = u.e;
80181074Sdas	    c  = (z-df*df)/(s+df);
81181074Sdas	    p = P(z);
82181074Sdas	    q = Q(z);
83181074Sdas	    r = p/q;
84181074Sdas	    w = r*s+c;
85181074Sdas	    return 2.0*(df+w);
86181074Sdas	}
87181074Sdas}
88