xref: /illumos-gate/usr/src/lib/libm/common/C/jn.c (revision fe4627ef755b7c263f91a0e6f07cdca5d7083501)
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 __jn = jn
31 #pragma weak __yn = yn
32 
33 /*
34  * floating point Bessel's function of the 1st and 2nd kind
35  * of order n: jn(n,x),yn(n,x);
36  *
37  * Special cases:
38  *	y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
39  *	y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
40  * Note 2. About jn(n,x), yn(n,x)
41  *	For n=0, j0(x) is called,
42  *	for n=1, j1(x) is called,
43  *	for n<x, forward recursion us used starting
44  *	from values of j0(x) and j1(x).
45  *	for n>x, a continued fraction approximation to
46  *	j(n,x)/j(n-1,x) is evaluated and then backward
47  *	recursion is used starting from a supposed value
48  *	for j(n,x). The resulting value of j(0,x) is
49  *	compared with the actual value to correct the
50  *	supposed value of j(n,x).
51  *
52  *	yn(n,x) is similar in all respects, except
53  *	that forward recursion is used for all
54  *	values of n>1.
55  *
56  */
57 
58 #include "libm.h"
59 #include <float.h>	/* DBL_MIN */
60 #include <values.h>	/* X_TLOSS */
61 #include "xpg6.h"	/* __xpg6 */
62 
63 #define	GENERIC double
64 
65 static const GENERIC
66 	invsqrtpi = 5.641895835477562869480794515607725858441e-0001,
67 	two	= 2.0,
68 	zero	= 0.0,
69 	one	= 1.0;
70 
71 GENERIC
72 jn(int n, GENERIC x) {
73 	int i, sgn;
74 	GENERIC a, b, temp = 0;
75 	GENERIC z, w, ox, on;
76 
77 	/*
78 	 * J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
79 	 * Thus, J(-n,x) = J(n,-x)
80 	 */
81 	ox = x; on = (GENERIC)n;
82 	if (n < 0) {
83 		n = -n;
84 		x = -x;
85 	}
86 	if (isnan(x))
87 		return (x*x);	/* + -> * for Cheetah */
88 	if (!((int) _lib_version == libm_ieee ||
89 		(__xpg6 & _C99SUSv3_math_errexcept) != 0)) {
90 	    if (fabs(x) > X_TLOSS)
91 			return (_SVID_libm_err(on, ox, 38));
92 	}
93 	if (n == 0)
94 		return (j0(x));
95 	if (n == 1)
96 		return (j1(x));
97 	if ((n&1) == 0)
98 		sgn = 0; 			/* even n */
99 	else
100 		sgn = signbit(x);	/* old n  */
101 	x = fabs(x);
102 	if (x == zero||!finite(x)) b = zero;
103 	else if ((GENERIC)n <= x) {
104 					/*
105 					 * Safe to use
106 					 *  J(n+1,x)=2n/x *J(n,x)-J(n-1,x)
107 					 */
108 	    if (x > 1.0e91) {
109 				/*
110 				 * x >> n**2
111 				 *    Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
112 				 *   Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
113 				 *   Let s=sin(x), c=cos(x),
114 				 *	xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
115 				 *
116 				 *	   n	sin(xn)*sqt2	cos(xn)*sqt2
117 				 *	----------------------------------
118 				 *	   0	 s-c		 c+s
119 				 *	   1	-s-c 		-c+s
120 				 *	   2	-s+c		-c-s
121 				 *	   3	 s+c		 c-s
122 				 */
123 		switch (n&3) {
124 		    case 0: temp =  cos(x)+sin(x); break;
125 		    case 1: temp = -cos(x)+sin(x); break;
126 		    case 2: temp = -cos(x)-sin(x); break;
127 		    case 3: temp =  cos(x)-sin(x); break;
128 		}
129 		b = invsqrtpi*temp/sqrt(x);
130 	    } else {
131 			a = j0(x);
132 			b = j1(x);
133 			for (i = 1; i < n; i++) {
134 		    temp = b;
135 		    b = b*((GENERIC)(i+i)/x) - a; /* avoid underflow */
136 		    a = temp;
137 			}
138 	    }
139 	} else {
140 	    if (x < 1e-9) {	/* use J(n,x) = 1/n!*(x/2)^n */
141 		b = pow(0.5*x, (GENERIC) n);
142 		if (b != zero) {
143 		    for (a = one, i = 1; i <= n; i++) a *= (GENERIC)i;
144 		    b = b/a;
145 		}
146 	    } else {
147 		/*
148 		 * use backward recurrence
149 		 * 			x	  x^2	  x^2
150 		 *  J(n,x)/J(n-1,x) =  ----   ------   ------   .....
151 		 *			2n  - 2(n+1) - 2(n+2)
152 		 *
153 		 * 			1	  1	    1
154 		 *  (for large x)   =  ----  ------   ------   .....
155 		 *			2n   2(n+1)   2(n+2)
156 		 *			-- - ------ - ------ -
157 		 *			 x	 x		 x
158 		 *
159 		 * Let w = 2n/x and h = 2/x, then the above quotient
160 		 * is equal to the continued fraction:
161 		 *		    1
162 		 *	= -----------------------
163 		 *			   1
164 		 *	   w - -----------------
165 		 *			  1
166 		 * 			w+h - ---------
167 		 *			   w+2h - ...
168 		 *
169 		 * To determine how many terms needed, let
170 		 * Q(0) = w, Q(1) = w(w+h) - 1,
171 		 * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
172 		 * When Q(k) > 1e4	good for single
173 		 * When Q(k) > 1e9	good for double
174 		 * When Q(k) > 1e17	good for quaduple
175 		 */
176 	    /* determin k */
177 		GENERIC t, v;
178 		double q0, q1, h, tmp; int k, m;
179 		w  = (n+n)/(double)x; h = 2.0/(double)x;
180 		q0 = w;  z = w + h; q1 = w*z - 1.0; k = 1;
181 		while (q1 < 1.0e9) {
182 			k += 1; z += h;
183 			tmp = z*q1 - q0;
184 			q0 = q1;
185 			q1 = tmp;
186 		}
187 		m = n+n;
188 		for (t = zero, i = 2*(n+k); i >= m; i -= 2) t = one/(i/x-t);
189 		a = t;
190 		b = one;
191 		/*
192 		 * estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
193 		 *  hence, if n*(log(2n/x)) > ...
194 		 *  single 8.8722839355e+01
195 		 *  double 7.09782712893383973096e+02
196 		 *  long double 1.1356523406294143949491931077970765006170e+04
197 		 *  then recurrent value may overflow and the result is
198 		 *  likely underflow to zero
199 		 */
200 		tmp = n;
201 		v = two/x;
202 		tmp = tmp*log(fabs(v*tmp));
203 		if (tmp < 7.09782712893383973096e+02) {
204 			    for (i = n-1; i > 0; i--) {
205 				temp = b;
206 				b = ((i+i)/x)*b - a;
207 			    a = temp;
208 				}
209 		} else {
210 				for (i = n-1; i > 0; i--) {
211 				    temp = b;
212 				    b = ((i+i)/x)*b - a;
213 				    a = temp;
214 					if (b > 1e100) {
215 						a /= b;
216 						t /= b;
217 						b  = 1.0;
218 					}
219 				}
220 		}
221 			b = (t*j0(x)/b);
222 	    }
223 	}
224 	if (sgn == 1)
225 		return (-b);
226 	else
227 		return (b);
228 }
229 
230 GENERIC
231 yn(int n, GENERIC x) {
232 	int i;
233 	int sign;
234 	GENERIC a, b, temp = 0, ox, on;
235 
236 	ox = x; on = (GENERIC)n;
237 	if (isnan(x))
238 		return (x*x);	/* + -> * for Cheetah */
239 	if (x <= zero) {
240 		if (x == zero) {
241 			/* return -one/zero; */
242 			return (_SVID_libm_err((GENERIC)n, x, 12));
243 		} else {
244 			/* return zero/zero; */
245 			return (_SVID_libm_err((GENERIC)n, x, 13));
246 		}
247 	}
248 	if (!((int) _lib_version == libm_ieee ||
249 		(__xpg6 & _C99SUSv3_math_errexcept) != 0)) {
250 	    if (x > X_TLOSS)
251 			return (_SVID_libm_err(on, ox, 39));
252 	}
253 	sign = 1;
254 	if (n < 0) {
255 		n = -n;
256 		if ((n&1) == 1) sign = -1;
257 	}
258 	if (n == 0)
259 		return (y0(x));
260 	if (n == 1)
261 		return (sign*y1(x));
262 	if (!finite(x))
263 		return (zero);
264 
265 	if (x > 1.0e91) {
266 				/*
267 				 * x >> n**2
268 				 *  Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
269 				 *  Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
270 				 *  Let s = sin(x), c = cos(x),
271 				 *  xn = x-(2n+1)*pi/4, sqt2 = sqrt(2), then
272 				 *
273 				 *    n	sin(xn)*sqt2	cos(xn)*sqt2
274 				 *	----------------------------------
275 				 *	 0	 s-c		 c+s
276 				 *	 1	-s-c 		-c+s
277 				 *	 2	-s+c		-c-s
278 				 *	 3	 s+c		 c-s
279 				 */
280 		switch (n&3) {
281 		    case 0: temp =  sin(x)-cos(x); break;
282 		    case 1: temp = -sin(x)-cos(x); break;
283 		    case 2: temp = -sin(x)+cos(x); break;
284 		    case 3: temp =  sin(x)+cos(x); break;
285 		}
286 		b = invsqrtpi*temp/sqrt(x);
287 	} else {
288 		a = y0(x);
289 		b = y1(x);
290 		/*
291 		 * fix 1262058 and take care of non-default rounding
292 		 */
293 		for (i = 1; i < n; i++) {
294 			temp = b;
295 			b *= (GENERIC) (i + i) / x;
296 			if (b <= -DBL_MAX)
297 				break;
298 			b -= a;
299 			a = temp;
300 		}
301 	}
302 	if (sign > 0)
303 		return (b);
304 	else
305 		return (-b);
306 }
307