]>
Commit | Line | Data |
---|---|---|
7ce331c0 EA |
1 | /* |
2 | * ==================================================== | |
3 | * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. | |
4 | * | |
5 | * Developed at SunPro, a Sun Microsystems, Inc. business. | |
6 | * Permission to use, copy, modify, and distribute this | |
c4e44e97 | 7 | * software is freely granted, provided that this notice |
7ce331c0 EA |
8 | * is preserved. |
9 | * ==================================================== | |
10 | */ | |
11 | ||
7ce331c0 EA |
12 | /* |
13 | * __ieee754_jn(n, x), __ieee754_yn(n, x) | |
14 | * floating point Bessel's function of the 1st and 2nd kind | |
15 | * of order n | |
c4e44e97 | 16 | * |
7ce331c0 EA |
17 | * Special cases: |
18 | * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; | |
19 | * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. | |
20 | * Note 2. About jn(n,x), yn(n,x) | |
21 | * For n=0, j0(x) is called, | |
22 | * for n=1, j1(x) is called, | |
23 | * for n<x, forward recursion us used starting | |
24 | * from values of j0(x) and j1(x). | |
25 | * for n>x, a continued fraction approximation to | |
26 | * j(n,x)/j(n-1,x) is evaluated and then backward | |
27 | * recursion is used starting from a supposed value | |
28 | * for j(n,x). The resulting value of j(0,x) is | |
29 | * compared with the actual value to correct the | |
30 | * supposed value of j(n,x). | |
31 | * | |
32 | * yn(n,x) is similar in all respects, except | |
33 | * that forward recursion is used for all | |
34 | * values of n>1. | |
c4e44e97 | 35 | * |
7ce331c0 EA |
36 | */ |
37 | ||
38 | #include "math.h" | |
39 | #include "math_private.h" | |
40 | ||
7ce331c0 | 41 | static const double |
7ce331c0 EA |
42 | invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ |
43 | two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */ | |
44 | one = 1.00000000000000000000e+00; /* 0x3FF00000, 0x00000000 */ | |
45 | ||
7ce331c0 | 46 | static const double zero = 0.00000000000000000000e+00; |
7ce331c0 | 47 | |
38b7304e | 48 | double attribute_hidden __ieee754_jn(int n, double x) |
7ce331c0 EA |
49 | { |
50 | int32_t i,hx,ix,lx, sgn; | |
82ba14bc | 51 | double a, b, temp=0, di; |
7ce331c0 EA |
52 | double z, w; |
53 | ||
54 | /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) | |
55 | * Thus, J(-n,x) = J(n,-x) | |
56 | */ | |
57 | EXTRACT_WORDS(hx,lx,x); | |
58 | ix = 0x7fffffff&hx; | |
59 | /* if J(n,NaN) is NaN */ | |
60 | if((ix|((u_int32_t)(lx|-lx))>>31)>0x7ff00000) return x+x; | |
c4e44e97 | 61 | if(n<0){ |
7ce331c0 EA |
62 | n = -n; |
63 | x = -x; | |
64 | hx ^= 0x80000000; | |
65 | } | |
66 | if(n==0) return(__ieee754_j0(x)); | |
67 | if(n==1) return(__ieee754_j1(x)); | |
68 | sgn = (n&1)&(hx>>31); /* even n -- 0, odd n -- sign(x) */ | |
69 | x = fabs(x); | |
70 | if((ix|lx)==0||ix>=0x7ff00000) /* if x is 0 or inf */ | |
71 | b = zero; | |
c4e44e97 | 72 | else if((double)n<=x) { |
7ce331c0 EA |
73 | /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ |
74 | if(ix>=0x52D00000) { /* x > 2**302 */ | |
c4e44e97 | 75 | /* (x >> n**2) |
7ce331c0 EA |
76 | * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) |
77 | * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) | |
c4e44e97 | 78 | * Let s=sin(x), c=cos(x), |
7ce331c0 EA |
79 | * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then |
80 | * | |
81 | * n sin(xn)*sqt2 cos(xn)*sqt2 | |
82 | * ---------------------------------- | |
83 | * 0 s-c c+s | |
84 | * 1 -s-c -c+s | |
85 | * 2 -s+c -c-s | |
86 | * 3 s+c c-s | |
87 | */ | |
88 | switch(n&3) { | |
89 | case 0: temp = cos(x)+sin(x); break; | |
90 | case 1: temp = -cos(x)+sin(x); break; | |
91 | case 2: temp = -cos(x)-sin(x); break; | |
92 | case 3: temp = cos(x)-sin(x); break; | |
93 | } | |
94 | b = invsqrtpi*temp/sqrt(x); | |
c4e44e97 | 95 | } else { |
7ce331c0 EA |
96 | a = __ieee754_j0(x); |
97 | b = __ieee754_j1(x); | |
98 | for(i=1;i<n;i++){ | |
99 | temp = b; | |
100 | b = b*((double)(i+i)/x) - a; /* avoid underflow */ | |
101 | a = temp; | |
102 | } | |
103 | } | |
104 | } else { | |
105 | if(ix<0x3e100000) { /* x < 2**-29 */ | |
c4e44e97 | 106 | /* x is tiny, return the first Taylor expansion of J(n,x) |
7ce331c0 EA |
107 | * J(n,x) = 1/n!*(x/2)^n - ... |
108 | */ | |
109 | if(n>33) /* underflow */ | |
110 | b = zero; | |
111 | else { | |
112 | temp = x*0.5; b = temp; | |
113 | for (a=one,i=2;i<=n;i++) { | |
114 | a *= (double)i; /* a = n! */ | |
115 | b *= temp; /* b = (x/2)^n */ | |
116 | } | |
117 | b = b/a; | |
118 | } | |
119 | } else { | |
120 | /* use backward recurrence */ | |
c4e44e97 | 121 | /* x x^2 x^2 |
7ce331c0 EA |
122 | * J(n,x)/J(n-1,x) = ---- ------ ------ ..... |
123 | * 2n - 2(n+1) - 2(n+2) | |
124 | * | |
c4e44e97 | 125 | * 1 1 1 |
7ce331c0 EA |
126 | * (for large x) = ---- ------ ------ ..... |
127 | * 2n 2(n+1) 2(n+2) | |
c4e44e97 | 128 | * -- - ------ - ------ - |
7ce331c0 EA |
129 | * x x x |
130 | * | |
131 | * Let w = 2n/x and h=2/x, then the above quotient | |
132 | * is equal to the continued fraction: | |
133 | * 1 | |
134 | * = ----------------------- | |
135 | * 1 | |
136 | * w - ----------------- | |
137 | * 1 | |
138 | * w+h - --------- | |
139 | * w+2h - ... | |
140 | * | |
141 | * To determine how many terms needed, let | |
142 | * Q(0) = w, Q(1) = w(w+h) - 1, | |
143 | * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), | |
c4e44e97 EA |
144 | * When Q(k) > 1e4 good for single |
145 | * When Q(k) > 1e9 good for double | |
146 | * When Q(k) > 1e17 good for quadruple | |
7ce331c0 EA |
147 | */ |
148 | /* determine k */ | |
149 | double t,v; | |
150 | double q0,q1,h,tmp; int32_t k,m; | |
151 | w = (n+n)/(double)x; h = 2.0/(double)x; | |
152 | q0 = w; z = w+h; q1 = w*z - 1.0; k=1; | |
153 | while(q1<1.0e9) { | |
154 | k += 1; z += h; | |
155 | tmp = z*q1 - q0; | |
156 | q0 = q1; | |
157 | q1 = tmp; | |
158 | } | |
159 | m = n+n; | |
160 | for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t); | |
161 | a = t; | |
162 | b = one; | |
163 | /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) | |
164 | * Hence, if n*(log(2n/x)) > ... | |
165 | * single 8.8722839355e+01 | |
166 | * double 7.09782712893383973096e+02 | |
167 | * long double 1.1356523406294143949491931077970765006170e+04 | |
c4e44e97 | 168 | * then recurrent value may overflow and the result is |
7ce331c0 EA |
169 | * likely underflow to zero |
170 | */ | |
171 | tmp = n; | |
172 | v = two/x; | |
173 | tmp = tmp*__ieee754_log(fabs(v*tmp)); | |
174 | if(tmp<7.09782712893383973096e+02) { | |
175 | for(i=n-1,di=(double)(i+i);i>0;i--){ | |
176 | temp = b; | |
177 | b *= di; | |
178 | b = b/x - a; | |
179 | a = temp; | |
180 | di -= two; | |
181 | } | |
182 | } else { | |
183 | for(i=n-1,di=(double)(i+i);i>0;i--){ | |
184 | temp = b; | |
185 | b *= di; | |
186 | b = b/x - a; | |
187 | a = temp; | |
188 | di -= two; | |
189 | /* scale b to avoid spurious overflow */ | |
190 | if(b>1e100) { | |
191 | a /= b; | |
192 | t /= b; | |
193 | b = one; | |
194 | } | |
195 | } | |
196 | } | |
197 | b = (t*__ieee754_j0(x)/b); | |
198 | } | |
199 | } | |
200 | if(sgn==1) return -b; else return b; | |
201 | } | |
202 | ||
30bd4a6c DV |
203 | /* |
204 | * wrapper jn(int n, double x) | |
205 | */ | |
206 | #ifndef _IEEE_LIBM | |
207 | double jn(int n, double x) | |
208 | { | |
209 | double z = __ieee754_jn(n, x); | |
210 | if (_LIB_VERSION == _IEEE_ || isnan(x)) | |
211 | return z; | |
212 | if (fabs(x) > X_TLOSS) | |
213 | return __kernel_standard((double)n, x, 38); /* jn(|x|>X_TLOSS,n) */ | |
214 | return z; | |
215 | } | |
216 | #else | |
217 | strong_alias(__ieee754_jn, jn) | |
218 | #endif | |
219 | ||
38b7304e | 220 | double attribute_hidden __ieee754_yn(int n, double x) |
7ce331c0 EA |
221 | { |
222 | int32_t i,hx,ix,lx; | |
223 | int32_t sign; | |
82ba14bc | 224 | double a, b, temp=0; |
7ce331c0 EA |
225 | |
226 | EXTRACT_WORDS(hx,lx,x); | |
227 | ix = 0x7fffffff&hx; | |
228 | /* if Y(n,NaN) is NaN */ | |
229 | if((ix|((u_int32_t)(lx|-lx))>>31)>0x7ff00000) return x+x; | |
230 | if((ix|lx)==0) return -one/zero; | |
231 | if(hx<0) return zero/zero; | |
232 | sign = 1; | |
233 | if(n<0){ | |
234 | n = -n; | |
235 | sign = 1 - ((n&1)<<1); | |
236 | } | |
237 | if(n==0) return(__ieee754_y0(x)); | |
238 | if(n==1) return(sign*__ieee754_y1(x)); | |
239 | if(ix==0x7ff00000) return zero; | |
240 | if(ix>=0x52D00000) { /* x > 2**302 */ | |
c4e44e97 | 241 | /* (x >> n**2) |
7ce331c0 EA |
242 | * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) |
243 | * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) | |
c4e44e97 | 244 | * Let s=sin(x), c=cos(x), |
7ce331c0 EA |
245 | * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then |
246 | * | |
247 | * n sin(xn)*sqt2 cos(xn)*sqt2 | |
248 | * ---------------------------------- | |
249 | * 0 s-c c+s | |
250 | * 1 -s-c -c+s | |
251 | * 2 -s+c -c-s | |
252 | * 3 s+c c-s | |
253 | */ | |
254 | switch(n&3) { | |
255 | case 0: temp = sin(x)-cos(x); break; | |
256 | case 1: temp = -sin(x)-cos(x); break; | |
257 | case 2: temp = -sin(x)+cos(x); break; | |
258 | case 3: temp = sin(x)+cos(x); break; | |
259 | } | |
260 | b = invsqrtpi*temp/sqrt(x); | |
261 | } else { | |
262 | u_int32_t high; | |
263 | a = __ieee754_y0(x); | |
264 | b = __ieee754_y1(x); | |
265 | /* quit if b is -inf */ | |
266 | GET_HIGH_WORD(high,b); | |
c4e44e97 | 267 | for(i=1;i<n&&high!=0xfff00000;i++){ |
7ce331c0 EA |
268 | temp = b; |
269 | b = ((double)(i+i)/x)*b - a; | |
270 | GET_HIGH_WORD(high,b); | |
271 | a = temp; | |
272 | } | |
273 | } | |
274 | if(sign>0) return b; else return -b; | |
275 | } | |
30bd4a6c DV |
276 | |
277 | /* | |
278 | * wrapper yn(int n, double x) | |
279 | */ | |
280 | #ifndef _IEEE_LIBM | |
281 | double yn(int n, double x) /* wrapper yn */ | |
282 | { | |
283 | double z = __ieee754_yn(n, x); | |
284 | if (_LIB_VERSION == _IEEE_ || isnan(x)) | |
285 | return z; | |
286 | if (x <= 0.0) { | |
287 | if(x == 0.0) /* d= -one/(x-x); */ | |
288 | return __kernel_standard((double)n, x, 12); | |
289 | /* d = zero/(x-x); */ | |
290 | return __kernel_standard((double)n, x, 13); | |
291 | } | |
292 | if (x > X_TLOSS) | |
293 | return __kernel_standard((double)n, x, 39); /* yn(x>X_TLOSS,n) */ | |
294 | return z; | |
295 | } | |
296 | #else | |
297 | strong_alias(__ieee754_yn, yn) | |
298 | #endif |