My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cbesselj.cpp
Go to the documentation of this file.
1 /*
2  * cbesselj.cpp - Bessel function of first kind
3  *
4  * Copyright (C) 2007 Bastien Roucaries <roucaries.bastien@gmail.com>
5  *
6  * This is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This software is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this package; see the file COPYING. If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  * $Id: cbesselj.cpp 1825 2011-03-11 20:42:14Z ela $
22  *
23  */
24 
60 #if HAVE_CONFIG_H
61 # include <config.h>
62 #endif
63 
64 #include <math.h>
65 #include <assert.h>
66 #include <errno.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 
70 #include "complex.h"
71 #include "constants.h"
72 #include "precision.h"
73 
74 #define SMALL_J0_BOUND 1e6
75 
77 #define SMALL_JN_BOUND 5.0
78 
80 #define BIG_JN_BOUND 25.0
81 
83 #define MAX_SMALL_ITERATION 2048
84 
85 
103 static nr_complex_t
104 cbesselj_smallarg (unsigned int n, nr_complex_t z)
105 {
106  nr_complex_t ak, Rk;
107  nr_complex_t R;
108  nr_complex_t R0;
109  unsigned int k;
110 
111  /* a_0 */
112  errno = 0;
113  ak = pow (0.5 * z, n);
114  /* underflow */
115  if (errno == ERANGE)
116  {
117  return n > 0 ? 0.0 : 1;
118  }
119 
120  ak = ak / (nr_double_t) factorial (n);
121 
122  /* R_0 */
123  R0 = ak * 1.0;
124  Rk = R0;
125  R = R0;
126 
127  for (k = 1; k < MAX_SMALL_ITERATION; k++)
128  {
129  ak = -(z * z) / (4.0 * k * (n + k));
130  Rk = ak * Rk;
131  if (fabs (real (Rk)) < fabs (real (R) * NR_EPSI) &&
132  fabs (imag (Rk)) < fabs (imag (R) * NR_EPSI))
133  return R;
134 
135  R += Rk;
136  }
137  /* impossible */
138  assert (k < MAX_SMALL_ITERATION);
139  abort ();
140 }
141 
142 
143 static nr_complex_t
144 cbesselj_mediumarg_odd (unsigned int n, nr_complex_t z)
145 {
146  nr_complex_t first, second;
147  nr_complex_t ak;
148 
149  unsigned int m;
150  unsigned int k;
151  nr_double_t t;
152  nr_double_t m1pna2;
153 
154  m = (2 * abs (z) + 0.25 * (n + abs (imag (z))));
155 
156  /* -1^(n/2) */
157  m1pna2 = (n / 2) % 2 == 0 ? 1.0 : -1.0;
158  first = (1.0 + m1pna2 * cos (z)) / (2.0 * m);
159 
160  second = 0.0;
161  for (k = 1; k <= m - 1; k++)
162  {
163  t = (k * M_PI) / (2 * m);
164  ak = cos (z * sin (t)) * cos (n * t);
165  second += ak;
166  }
167  return first + second / (nr_double_t) m;
168 }
169 
170 static nr_complex_t
171 cbesselj_mediumarg_even (unsigned int n, nr_complex_t z)
172 {
173  nr_complex_t first, second;
174  nr_complex_t ak;
175 
176  unsigned int m;
177  unsigned int k;
178  nr_double_t t;
179  nr_double_t m1pn1a2;
180 
181  m = (2 * abs (z) + 0.25 * (n + abs (imag (z))));
182 
183  /* -1^(n/2) */
184  m1pn1a2 = ((n - 1) / 2) % 2 == 0 ? 1.0 : -1.0;
185  first = (m1pn1a2 * sin (z)) / (2.0 * m);
186 
187  second = 0.0;
188  for (k = 1; k <= m - 1; k++)
189  {
190  t = (k * M_PI) / (2 * m);
191  ak = sin (z * sin (t)) * sin (n * t);
192  second += ak;
193  }
194  return first + second / (nr_double_t) m;
195 }
196 
197 
198 static nr_complex_t
199 cbesselj_mediumarg (unsigned int n, nr_complex_t z)
200 {
201  if (n % 2 == 0)
202  return cbesselj_mediumarg_odd (n, z);
203  else
204  return cbesselj_mediumarg_even (n, z);
205 }
206 
207 
208 
210 #define MAX_LARGE_ITERATION 430
211 
216 static nr_complex_t
217 cbesselj_largearg (unsigned int n, nr_complex_t z)
218 {
219  nr_complex_t Pk, P0, P, Qk, Q0, Q_;
220  nr_complex_t tmp;
221  unsigned long num, denum;
222  nr_complex_t m1a8z2;
223  unsigned int k;
224  nr_double_t l, m;
225 
226  /* P0 & Q0 */
227  P0 = 1;
228  P = P0;
229  Pk = P0;
230 
231  Q0 = (4.0 * n * n - 1) / (8.0 * z);
232  Q_ = Q0;
233  Qk = Q0;
234 
235  m1a8z2 = (-1.0) / (8.0 * sqr (z));
236 
237  /* P */
238  for (k = 1;; k++)
239  {
240  /* Usually converge before overflow */
241  assert (k <= MAX_LARGE_ITERATION);
242 
243  num = (4 * sqr (n) - sqr (4 * k - 3)) * (4 * sqr (n) - (4 * k - 1));
244  denum = 2 * k * (2 * k - 1);
245  Pk = Pk * ((nr_double_t) num * m1a8z2) / ((nr_double_t) denum);
246 
247  if (real (Pk) < real (P0) * NR_EPSI &&
248  imag (Pk) < imag (P0) * NR_EPSI)
249  break;
250 
251  P += Pk;
252  }
253 
254  /* P */
255  for (k = 1;; k++)
256  {
257  /* Usually converge before overflow */
258  assert (k <= MAX_LARGE_ITERATION);
259 
260  num = (4 * sqr (n) - sqr (4 * k - 1)) * (4 * sqr (n) - (4 * k - 1));
261  denum = 2 * k * (2 * k - 1);
262  Qk = Qk * ((nr_double_t) num * m1a8z2) / ((nr_double_t) denum);
263 
264  if (real (Qk) < real (Q0) * NR_EPSI ||
265  imag (Qk) < imag (Q0) * NR_EPSI)
266  break;
267 
268  Q_ += Qk;
269  }
270 
271  /* l, m cf [5] eq (5) */
272  l = (n % 4 == 0) || (n % 4 == 3) ? 1.0 : -1.0;
273  m = (n % 4 == 0) || (n % 4 == 1) ? 1.0 : -1.0;
274 
275 
276  tmp = (l * P + m * Q_) * cos (z);
277  tmp += (m * P - l * Q_) * sin (z);
278  return tmp / sqrt (M_PI * z);
279 }
280 
285 cbesselj (unsigned int n, nr_complex_t z)
286 {
287  nr_double_t mul = 1.0;
288  nr_complex_t ret;
289 
290  /* J_n(-z)=(-1)^n J_n(z) */
291  /*
292  if(real(z) < 0.0)
293  {
294  z = -z;
295  mul = (n % 2) == 0 ? 1.0 : -1.0 ;
296  }
297  */
298  if (abs (z) < SMALL_JN_BOUND)
299  ret = cbesselj_smallarg (n, z);
300  else if (abs (z) > BIG_JN_BOUND)
301  ret = cbesselj_largearg (n, z);
302  else
303  ret = cbesselj_mediumarg (n, z);
304 
305  return mul * ret;
306 }