vigra - vigra/bessel.hxx Source File

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

bessel.hxx |

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

© 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.10.0 (Mon Nov 18 2013)