xref: /freebsd-src/lib/msun/ld80/b_expl.c (revision 03a88e3de9c68182d21df94b1c8c7ced930dbd1f)
1*03a88e3dSMark Murray /*-
2*03a88e3dSMark Murray  * SPDX-License-Identifier: BSD-3-Clause
3*03a88e3dSMark Murray  *
4*03a88e3dSMark Murray  * Copyright (c) 1985, 1993
5*03a88e3dSMark Murray  *	The Regents of the University of California.  All rights reserved.
6*03a88e3dSMark Murray  *
7*03a88e3dSMark Murray  * Redistribution and use in source and binary forms, with or without
8*03a88e3dSMark Murray  * modification, are permitted provided that the following conditions
9*03a88e3dSMark Murray  * are met:
10*03a88e3dSMark Murray  * 1. Redistributions of source code must retain the above copyright
11*03a88e3dSMark Murray  *    notice, this list of conditions and the following disclaimer.
12*03a88e3dSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
13*03a88e3dSMark Murray  *    notice, this list of conditions and the following disclaimer in the
14*03a88e3dSMark Murray  *    documentation and/or other materials provided with the distribution.
15*03a88e3dSMark Murray  * 3. Neither the name of the University nor the names of its contributors
16*03a88e3dSMark Murray  *    may be used to endorse or promote products derived from this software
17*03a88e3dSMark Murray  *    without specific prior written permission.
18*03a88e3dSMark Murray  *
19*03a88e3dSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20*03a88e3dSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*03a88e3dSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*03a88e3dSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23*03a88e3dSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*03a88e3dSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*03a88e3dSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*03a88e3dSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*03a88e3dSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*03a88e3dSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*03a88e3dSMark Murray  * SUCH DAMAGE.
30*03a88e3dSMark Murray  */
31*03a88e3dSMark Murray 
32*03a88e3dSMark Murray /*
33*03a88e3dSMark Murray  * See bsdsrc/b_exp.c for implementation details.
34*03a88e3dSMark Murray  *
35*03a88e3dSMark Murray  * bsdrc/b_exp.c converted to long double by Steven G. Kargl.
36*03a88e3dSMark Murray  */
37*03a88e3dSMark Murray 
38*03a88e3dSMark Murray #include "fpmath.h"
39*03a88e3dSMark Murray #include "math_private.h"
40*03a88e3dSMark Murray 
41*03a88e3dSMark Murray static const union IEEEl2bits
42*03a88e3dSMark Murray     p0u = LD80C(0xaaaaaaaaaaaaaaab,    -3,  1.66666666666666666671e-01L),
43*03a88e3dSMark Murray     p1u = LD80C(0xb60b60b60b60b59a,    -9, -2.77777777777777775377e-03L),
44*03a88e3dSMark Murray     p2u = LD80C(0x8ab355e008a3cfce,   -14,  6.61375661375629297465e-05L),
45*03a88e3dSMark Murray     p3u = LD80C(0xddebbc994b0c1376,   -20, -1.65343915327882529784e-06L),
46*03a88e3dSMark Murray     p4u = LD80C(0xb354784cb4ef4c41,   -25,  4.17535101591534118469e-08L),
47*03a88e3dSMark Murray     p5u = LD80C(0x913e8a718382ce75,   -30, -1.05679137034774806475e-09L),
48*03a88e3dSMark Murray     p6u = LD80C(0xe8f0042aa134502e,   -36,  2.64819349895429516863e-11L);
49*03a88e3dSMark Murray #define	p1	(p0u.e)
50*03a88e3dSMark Murray #define	p2	(p1u.e)
51*03a88e3dSMark Murray #define	p3	(p2u.e)
52*03a88e3dSMark Murray #define	p4	(p3u.e)
53*03a88e3dSMark Murray #define	p5	(p4u.e)
54*03a88e3dSMark Murray #define	p6	(p5u.e)
55*03a88e3dSMark Murray #define	p7	(p6u.e)
56*03a88e3dSMark Murray 
57*03a88e3dSMark Murray /*
58*03a88e3dSMark Murray  * lnhuge = (LDBL_MAX_EXP + 9) * log(2.)
59*03a88e3dSMark Murray  * lntiny = (LDBL_MIN_EXP - 64 - 10) * log(2.)
60*03a88e3dSMark Murray  * invln2 = 1 / log(2.)
61*03a88e3dSMark Murray  */
62*03a88e3dSMark Murray static const union IEEEl2bits
63*03a88e3dSMark Murray ln2hiu  = LD80C(0xb17217f700000000,  -1,  6.93147180369123816490e-01L),
64*03a88e3dSMark Murray ln2lou  = LD80C(0xd1cf79abc9e3b398, -33,  1.90821492927058781614e-10L),
65*03a88e3dSMark Murray lnhugeu = LD80C(0xb18b0c0330a8fad9,  13,  1.13627617309191834574e+04L),
66*03a88e3dSMark Murray lntinyu = LD80C(0xb236f28a68bc3bd7,  13, -1.14057368561139000667e+04L),
67*03a88e3dSMark Murray invln2u = LD80C(0xb8aa3b295c17f0bc,   0,  1.44269504088896340739e+00L);
68*03a88e3dSMark Murray #define	ln2hi	(ln2hiu.e)
69*03a88e3dSMark Murray #define ln2lo	(ln2lou.e)
70*03a88e3dSMark Murray #define lnhuge	(lnhugeu.e)
71*03a88e3dSMark Murray #define	lntiny	(lntinyu.e)
72*03a88e3dSMark Murray #define	invln2	(invln2u.e)
73*03a88e3dSMark Murray 
74*03a88e3dSMark Murray /* returns exp(r = x + c) for |c| < |x| with no overlap.  */
75*03a88e3dSMark Murray 
76*03a88e3dSMark Murray static long double
__exp__D(long double x,long double c)77*03a88e3dSMark Murray __exp__D(long double x, long double c)
78*03a88e3dSMark Murray {
79*03a88e3dSMark Murray 	long double hi, lo, z;
80*03a88e3dSMark Murray 	int k;
81*03a88e3dSMark Murray 
82*03a88e3dSMark Murray 	if (x != x)	/* x is NaN. */
83*03a88e3dSMark Murray 		return(x);
84*03a88e3dSMark Murray 
85*03a88e3dSMark Murray 	if (x <= lnhuge) {
86*03a88e3dSMark Murray 		if (x >= lntiny) {
87*03a88e3dSMark Murray 			/* argument reduction: x --> x - k*ln2 */
88*03a88e3dSMark Murray 			z = invln2 * x;
89*03a88e3dSMark Murray 			k = z + copysignl(0.5L, x);
90*03a88e3dSMark Murray 
91*03a88e3dSMark Murray 		    	/*
92*03a88e3dSMark Murray 			 * Express (x + c) - k * ln2 as hi - lo.
93*03a88e3dSMark Murray 			 * Let x = hi - lo rounded.
94*03a88e3dSMark Murray 			 */
95*03a88e3dSMark Murray 			hi = x - k * ln2hi;	/* Exact. */
96*03a88e3dSMark Murray 			lo = k * ln2lo - c;
97*03a88e3dSMark Murray 			x = hi - lo;
98*03a88e3dSMark Murray 
99*03a88e3dSMark Murray 			/* Return 2^k*[1+x+x*c/(2+c)]  */
100*03a88e3dSMark Murray 			z = x * x;
101*03a88e3dSMark Murray 			c = x - z * (p1 + z * (p2 + z * (p3 + z * (p4 +
102*03a88e3dSMark Murray 			    z * (p5 + z * (p6 + z * p7))))));
103*03a88e3dSMark Murray 			c = (x * c) / (2 - c);
104*03a88e3dSMark Murray 
105*03a88e3dSMark Murray 			return (ldexpl(1 + (hi - (lo - c)), k));
106*03a88e3dSMark Murray 		} else {
107*03a88e3dSMark Murray 			/* exp(-INF) is 0. exp(-big) underflows to 0.  */
108*03a88e3dSMark Murray 			return (isfinite(x) ? ldexpl(1., -5000) : 0);
109*03a88e3dSMark Murray 		}
110*03a88e3dSMark Murray 	} else
111*03a88e3dSMark Murray 		/* exp(INF) is INF, exp(+big#) overflows to INF */
112*03a88e3dSMark Murray 		return (isfinite(x) ? ldexpl(1., 5000) : x);
113*03a88e3dSMark Murray }
114