[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

bessel.hxx VIGRA

1 /************************************************************************/
2 /* */
3 /* Copyright 2010-2011 by Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35 
36 #ifndef VIGRA_BESSEL_HXX
37 #define VIGRA_BESSEL_HXX
38 
39 #include "mathutil.hxx"
40 
41 #ifdef HasBoostMath
42 #include <boost/math/special_functions/bessel.hpp>
43 #endif
44 
45 namespace vigra {
46 
47 /** \addtogroup MathFunctions
48 */
49 //@{
50 
51 namespace detail {
52 
53 template <class REAL>
54 int msta1(REAL x, int mp)
55 {
56  double a0,f0,f1,f;
57  int i,n0,n1,nn;
58 
59  a0 = abs(x);
60  n0 = (int)(1.1*a0)+1;
61  f0 = 0.5*std::log10(6.28*n0) - n0*std::log10(1.36*a0/n0)-mp;
62  n1 = n0+5;
63  f1 = 0.5*std::log10(6.28*n1) - n1*std::log10(1.36*a0/n1)-mp;
64  for(i=0;i<20;i++)
65  {
66  nn = int(n1-(n1-n0)/(1.0-f0/f1));
67  f = 0.5*std::log10(6.28*nn) - nn*std::log10(1.36*a0/nn)-mp;
68  if(abs(nn-n1) < 1)
69  break;
70  n0 = n1;
71  f0 = f1;
72  n1 = nn;
73  f1 = f;
74  }
75  return nn;
76 }
77 
78 template <class REAL>
79 int msta2(REAL x, int n, int mp)
80 {
81  double a0,ejn,hmp,f0,f1,f,obj;
82  int i,n0,n1,nn;
83 
84  a0 = abs(x);
85  hmp = 0.5*mp;
86  ejn = 0.5*std::log10(6.28*n) - n*std::log10(1.36*a0/n);
87  if (ejn <= hmp)
88  {
89  obj = mp;
90  n0 = (int)(1.1*a0);
91  if (n0 < 1)
92  n0 = 1;
93  }
94  else
95  {
96  obj = hmp+ejn;
97  n0 = n;
98  }
99  f0 = 0.5*std::log10(6.28*n0) - n0*std::log10(1.36*a0/n0)-obj;
100  n1 = n0+5;
101  f1 = 0.5*std::log10(6.28*n1) - n1*std::log10(1.36*a0/n1)-obj;
102  for (i=0;i<20;i++)
103  {
104  nn = int(n1-(n1-n0)/(1.0-f0/f1));
105  f = 0.5*std::log10(6.28*nn) - nn*std::log10(1.36*a0/nn)-obj;
106  if (abs(nn-n1) < 1)
107  break;
108  n0 = n1;
109  f0 = f1;
110  n1 = nn;
111  f1 = f;
112  }
113  return nn+10;
114 }
115 
116 //
117 // INPUT:
118 // double x -- argument of Bessel function of 1st and 2nd kind.
119 // int n -- order
120 //
121 // OUPUT:
122 //
123 // int nm -- highest order actually computed (nm <= n)
124 // double jn[] -- Bessel function of 1st kind, orders from 0 to nm
125 // double yn[] -- Bessel function of 2nd kind, orders from 0 to nm
126 //
127 // Computes Bessel functions of all order up to 'n' using recurrence
128 // relations. If 'nm' < 'n' only 'nm' orders are returned.
129 //
130 // code has been adapted from C.R. Bond's implementation
131 // see http://www.crbond.com/math.htm
132 //
133 template <class REAL>
134 void bessjyn(int n, REAL x,int &nm, double *jn, double *yn)
135 {
136  double t1,t2,f,f1,f2,bj0,bj1,bjk,by0,by1,cu,s0,su,sv;
137  double ec,bs,byk,p0,p1,q0,q1;
138  double a[] = {
139  -0.7031250000000000e-1,
140  0.1121520996093750,
141  -0.5725014209747314,
142  6.074042001273483};
143  double b[] = {
144  0.7324218750000000e-1,
145  -0.2271080017089844,
146  1.727727502584457,
147  -2.438052969955606e1};
148  double a1[] = {
149  0.1171875,
150  -0.1441955566406250,
151  0.6765925884246826,
152  -6.883914268109947};
153  double b1[] = {
154  -0.1025390625,
155  0.2775764465332031,
156  -1.993531733751297,
157  2.724882731126854e1};
158 
159  int i,k,m;
160  nm = n;
161  if (x < 1e-15)
162  {
163  for (i=0;i<=n;i++)
164  {
165  jn[i] = 0.0;
166  yn[i] = -1e308;
167  }
168  jn[0] = 1.0;
169  return;
170  }
171  if (x <= 300.0 || n > (int)(0.9*x))
172  {
173  if (n == 0)
174  nm = 1;
175  m = msta1(x,200);
176  if (m < nm)
177  nm = m;
178  else
179  m = msta2(x,nm,15);
180  bs = 0.0;
181  su = 0.0;
182  sv = 0.0;
183  f2 = 0.0;
184  f1 = 1.0e-100;
185  for (k = m;k>=0;k--)
186  {
187  f = 2.0*(k+1.0)/x*f1 - f2;
188  if (k <= nm)
189  jn[k] = f;
190  if ((k == 2*(int)(k/2)) && (k != 0))
191  {
192  bs += 2.0*f;
193  su += (-1)*((k & 2)-1)*f/(double)k;
194  }
195  else if (k > 1)
196  {
197  sv += (-1)*((k & 2)-1)*(double)k*f/(k*k-1.0);
198  }
199  f2 = f1;
200  f1 = f;
201  }
202  s0 = bs+f;
203  for (k=0;k<=nm;k++)
204  {
205  jn[k] /= s0;
206  }
207  ec = std::log(0.5*x) + M_EULER_GAMMA;
208  by0 = M_2_PI*(ec*jn[0]-4.0*su/s0);
209  yn[0] = by0;
210  by1 = M_2_PI*((ec-1.0)*jn[1]-jn[0]/x-4.0*sv/s0);
211  yn[1] = by1;
212  }
213  else
214  {
215  t1 = x-M_PI_4;
216  p0 = 1.0;
217  q0 = -0.125/x;
218  for (k=0;k<4;k++)
219  {
220  p0 += a[k]*std::pow(x,-2*k-2);
221  q0 += b[k]*std::pow(x,-2*k-3);
222  }
223  cu = std::sqrt(M_2_PI/x);
224  bj0 = cu*(p0*std::cos(t1)-q0*std::sin(t1));
225  by0 = cu*(p0*std::sin(t1)+q0*std::cos(t1));
226  jn[0] = bj0;
227  yn[0] = by0;
228  t2 = x-0.75*M_PI;
229  p1 = 1.0;
230  q1 = 0.375/x;
231  for (k=0;k<4;k++)
232  {
233  p1 += a1[k]*std::pow(x,-2*k-2);
234  q1 += b1[k]*std::pow(x,-2*k-3);
235  }
236  bj1 = cu*(p1*std::cos(t2)-q1*std::sin(t2));
237  by1 = cu*(p1*std::sin(t2)+q1*std::cos(t2));
238  jn[1] = bj1;
239  yn[1] = by1;
240  for (k=2;k<=nm;k++)
241  {
242  bjk = 2.0*(k-1.0)*bj1/x-bj0;
243  jn[k] = bjk;
244  bj0 = bj1;
245  bj1 = bjk;
246  }
247  }
248  for (k=2;k<=nm;k++)
249  {
250  byk = 2.0*(k-1.0)*by1/x-by0;
251  yn[k] = byk;
252  by0 = by1;
253  by1 = byk;
254  }
255 }
256 
257 
258 
259 } // namespace detail
260 
261  /** \brief Bessel function of the first kind.
262 
263  Computes the value of BesselJ of integer order <tt>n</tt> and argument <tt>x</tt>.
264  Negative <tt>x</tt> are unsupported and will result in a <tt>std::domain_error</tt>.
265 
266  This function wraps a number of existing implementations and falls back to
267  a rather slow algorithm if none of them is available. In particular,
268  it uses boost::math when <tt>HasBoostMath</tt> is \#defined, or native
269  implementations on gcc and MSVC otherwise.
270 
271  <b>\#include</b> <vigra/bessel.hxx><br>
272  Namespace: vigra
273  */
274 inline double besselJ(int n, double x)
275 {
276  if(x < 0.0)
277  throw std::domain_error("besselJ(n, x): x cannot be negative");
278  if(x < 1e-15)
279  return n == 0 ? 1.0 : 0.0;
280 #if defined(HasBoostMath)
281  return boost::math::cyl_bessel_j((double)n, x);
282 #elif defined(__GNUC__)
283  return ::jn(n, x);
284 #elif defined(_MSC_VER)
285  return _jn(n, x);
286 #else
287  int an = abs(n), nr = n, s = an+2;
288  ArrayVector<double> t(2*s);
289  detail::bessjyn(an, x, nr, &t[0], &t[s]);
290  if(n < 0 && odd(an))
291  return -t[an];
292  else
293  return t[an];
294 #endif
295 }
296 
297  /** \brief Bessel function of the second kind.
298 
299  Computes the value of BesselY of integer order <tt>n</tt> and argument <tt>x</tt>.
300  Negative <tt>x</tt> are unsupported and will result in a <tt>std::domain_error</tt>.
301 
302  This function wraps a number of existing implementations and falls back to
303  a rather slow algorithm if none of them is available. In particular,
304  it uses boost::math when <tt>HasBoostMath</tt> is \#defined, or native
305  implementations on gcc and MSVC otherwise.
306 
307  <b>\#include</b> <vigra/bessel.hxx><br>
308  Namespace: vigra
309  */
310 inline double besselY(int n, double x)
311 {
312  if(x < 0.0)
313  throw std::domain_error("besselY(n, x): x cannot be negative");
314  if(x == 0.0 )
315  return -std::numeric_limits<double>::infinity();
316 #if defined(HasBoostMath)
317  return boost::math::cyl_neumann((double)n, x);
318 #elif defined(__GNUC__)
319  return ::yn(n, x);
320 #elif defined(_MSC_VER)
321  return _yn(n, x);
322 #else
323  int an = abs(n), nr = n, s = an+2;
324  ArrayVector<double> t(2*s);
325  detail::bessjyn(an, x, nr, &t[0], &t[s]);
326  if(n < 0.0 && odd(n))
327  return -t[an+s];
328  else
329  return t[an+s];
330 #endif
331 }
332 
333 //@}
334 
335 } // namespace vigra
336 
337 #endif // VIGRA_BESSEL_HXX
linalg::TemporaryMatrix< T > sin(MultiArrayView< 2, T, C > const &v)
double besselJ(int n, double x)
Bessel function of the first kind.
Definition: bessel.hxx:274
bool odd(int t)
Check if an integer is odd.
linalg::TemporaryMatrix< T > log10(MultiArrayView< 2, T, C > const &v)
linalg::TemporaryMatrix< T > log(MultiArrayView< 2, T, C > const &v)
FFTWComplex< R >::NormType abs(const FFTWComplex< R > &a)
absolute value (= magnitude)
Definition: fftw3.hxx:1002
linalg::TemporaryMatrix< T > cos(MultiArrayView< 2, T, C > const &v)
double besselY(int n, double x)
Bessel function of the second kind.
Definition: bessel.hxx:310
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition: fixedpoint.hxx:616

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.11.1 (Fri May 19 2017)