1 /*	$OpenBSD: s_log1pl.c,v 1.3 2013/11/12 20:35:19 martynas Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*							log1pl.c
20  *
21  *      Relative error logarithm
22  *	Natural logarithm of 1+x, long double precision
23  *
24  *
25  *
26  * SYNOPSIS:
27  *
28  * long double x, y, log1pl();
29  *
30  * y = log1pl( x );
31  *
32  *
33  *
34  * DESCRIPTION:
35  *
36  * Returns the base e (2.718...) logarithm of 1+x.
37  *
38  * The argument 1+x is separated into its exponent and fractional
39  * parts.  If the exponent is between -1 and +1, the logarithm
40  * of the fraction is approximated by
41  *
42  *     log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x).
43  *
44  * Otherwise, setting  z = 2(x-1)/x+1),
45  *
46  *     log(x) = z + z^3 P(z)/Q(z).
47  *
48  *
49  *
50  * ACCURACY:
51  *
52  *                      Relative error:
53  * arithmetic   domain     # trials      peak         rms
54  *    IEEE     -1.0, 9.0    100000      8.2e-20    2.5e-20
55  *
56  * ERROR MESSAGES:
57  *
58  * log singularity:  x-1 = 0; returns -INFINITY
59  * log domain:       x-1 < 0; returns NAN
60  */
61 
62 
63 
64 /* Coefficients for log(1+x) = x - x^2 / 2 + x^3 P(x)/Q(x)
65  * 1/sqrt(2) <= x < sqrt(2)
66  * Theoretical peak relative error = 2.32e-20
67  */
68 
69 static long double P[] = {
70  4.5270000862445199635215E-5L,
71  4.9854102823193375972212E-1L,
72  6.5787325942061044846969E0L,
73  2.9911919328553073277375E1L,
74  6.0949667980987787057556E1L,
75  5.7112963590585538103336E1L,
76  2.0039553499201281259648E1L,
77 };
78 static long double Q[] = {
79 /* 1.0000000000000000000000E0,*/
80  1.5062909083469192043167E1L,
81  8.3047565967967209469434E1L,
82  2.2176239823732856465394E2L,
83  3.0909872225312059774938E2L,
84  2.1642788614495947685003E2L,
85  6.0118660497603843919306E1L,
86 };
87 
88 /* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2),
89  * where z = 2(x-1)/(x+1)
90  * 1/sqrt(2) <= x < sqrt(2)
91  * Theoretical peak relative error = 6.16e-22
92  */
93 
94 static long double R[4] = {
95  1.9757429581415468984296E-3L,
96 -7.1990767473014147232598E-1L,
97  1.0777257190312272158094E1L,
98 -3.5717684488096787370998E1L,
99 };
100 static long double S[4] = {
101 /* 1.00000000000000000000E0L,*/
102 -2.6201045551331104417768E1L,
103  1.9361891836232102174846E2L,
104 -4.2861221385716144629696E2L,
105 };
106 static const long double C1 = 6.9314575195312500000000E-1L;
107 static const long double C2 = 1.4286068203094172321215E-6L;
108 
109 #define SQRTH 0.70710678118654752440L
110 
111 long double
log1pl(long double xm1)112 log1pl(long double xm1)
113 {
114 long double x, y, z;
115 int e;
116 
117 if( isnan(xm1) )
118 	return(xm1 + xm1);
119 if( xm1 == (long double) INFINITY )
120 	return(xm1);
121 if(xm1 == 0.0l)
122 	return(xm1);
123 
124 x = xm1 + 1.0L;
125 
126 /* Test for domain errors.  */
127 if( x <= 0.0L )
128 	{
129 	if( x == 0.0L )
130                 return __math_divzerol(1);
131 	else
132 		return __math_invalidl(xm1);
133 	}
134 
135 /* Separate mantissa from exponent.
136    Use frexp so that denormal numbers will be handled properly.  */
137 x = frexpl( x, &e );
138 
139 /* logarithm using log(x) = z + z^3 P(z)/Q(z),
140    where z = 2(x-1)/x+1)  */
141 if( (e > 2) || (e < -2) )
142 {
143 if( x < SQRTH )
144 	{ /* 2( 2x-1 )/( 2x+1 ) */
145 	e -= 1;
146 	z = x - 0.5L;
147 	y = 0.5L * z + 0.5L;
148 	}
149 else
150 	{ /*  2 (x-1)/(x+1)   */
151 	z = x - 0.5L;
152 	z -= 0.5L;
153 	y = 0.5L * x  + 0.5L;
154 	}
155 x = z / y;
156 z = x*x;
157 z = x * ( z * __polevll( z, R, 3 ) / __p1evll( z, S, 3 ) );
158 z = z + e * C2;
159 z = z + x;
160 z = z + e * C1;
161 return( z );
162 }
163 
164 
165 /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */
166 
167 if( x < SQRTH )
168 	{
169 	e -= 1;
170 	if (e != 0)
171 	  x = 2.0l * x - 1.0L;
172 	else
173 	  x = xm1;
174 	}
175 else
176 	{
177 	  if (e != 0)
178 	    x = x - 1.0L;
179 	  else
180 	    x = xm1;
181 	}
182 z = x*x;
183 y = x * ( z * __polevll( x, P, 6 ) / __p1evll( x, Q, 6 ) );
184 y = y + e * C2;
185 z = y - 0.5l * z;
186 z = z + x;
187 z = z + e * C1;
188 return( z );
189 }
190