1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: bessel.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
32 #include "analysishelper.hxx"
34 #include <rtl/math.hxx>
36 using ::com::sun::star::lang::IllegalArgumentException
;
41 // ============================================================================
43 const double f_PI
= 3.1415926535897932385;
44 const double f_2_PI
= 2.0 * f_PI
;
45 const double f_PI_DIV_2
= f_PI
/ 2.0;
46 const double f_PI_DIV_4
= f_PI
/ 4.0;
47 const double f_2_DIV_PI
= 2.0 / f_PI
;
49 const double THRESHOLD
= 30.0; // Threshold for usage of approximation formula.
50 const double MAXEPSILON
= 1e-10; // Maximum epsilon for end of iteration.
51 const sal_Int32 MAXITER
= 100; // Maximum number of iterations.
54 // ============================================================================
56 // ============================================================================
58 /* The BESSEL function, first kind, unmodified:
60 inf (-1)^k (x/2)^(n+2k)
61 J_n(x) = SUM TERM(n,k) with TERM(n,k) := ---------------------
64 Approximation for the BESSEL function, first kind, unmodified, for great x:
66 J_n(x) ~ sqrt( 2 / (PI x) ) cos( x - n PI/2 - PI/4 ) for x>=0.
69 // ----------------------------------------------------------------------------
71 double BesselJ( double x
, sal_Int32 n
) throw( IllegalArgumentException
)
74 throw IllegalArgumentException();
77 if( fabs( x
) <= THRESHOLD
)
79 /* Start the iteration without TERM(n,0), which is set here.
81 TERM(n,0) = (x/2)^n / n!
83 double fTerm
= pow( x
/ 2.0, (double)n
) / Fak( n
);
84 sal_Int32 nK
= 1; // Start the iteration with k=1.
85 fResult
= fTerm
; // Start result with TERM(n,0).
87 const double fSqrX
= x
* x
/ -4.0;
91 /* Calculation of TERM(n,k) from TERM(n,k-1):
94 TERM(n,k) = ---------------------
97 (-1)(-1)^(k-1) (x/2)^2 (x/2)^(n+2(k-1))
98 = -----------------------------------------
99 k (k-1)! (n+k) (n+k-1)!
101 -(x/2)^2 (-1)^(k-1) (x/2)^(n+2(k-1))
102 = ---------- * -----------------------------
103 k(n+k) (k-1)! (n+k-1)!
106 = ---------- TERM(n,k-1)
109 fTerm
*= fSqrX
; // defined above as -(x^2/4)
110 fTerm
/= (nK
* (nK
+ n
));
113 while( (fabs( fTerm
) > MAXEPSILON
) && (++nK
< MAXITER
) );
117 /* Approximation for the BESSEL function, first kind, unmodified:
119 J_n(x) ~ sqrt( 2 / (PI x) ) cos( x - n PI/2 - PI/4 ) for x>=0.
121 The BESSEL function J_n with n IN {0,2,4,...} is axially symmetric at
122 x=0, means J_n(x) = J_n(-x). Therefore the approximation for x<0 is:
124 J_n(x) = J_n(|x|) for x<0 and n IN {0,2,4,...}.
126 The BESSEL function J_n with n IN {1,3,5,...} is point-symmetric at
127 x=0, means J_n(x) = -J_n(-x). Therefore the approximation for x<0 is:
129 J_n(x) = -J_n(|x|) for x<0 and n IN {1,3,5,...}.
131 double fXAbs
= fabs( x
);
132 fResult
= sqrt( f_2_DIV_PI
/ fXAbs
) * cos( fXAbs
- n
* f_PI_DIV_2
- f_PI_DIV_4
);
133 if( (n
& 1) && (x
< 0.0) )
140 // ============================================================================
142 // ============================================================================
144 /* The BESSEL function, first kind, modified:
147 I_n(x) = SUM TERM(n,k) with TERM(n,k) := --------------
150 Approximation for the BESSEL function, first kind, modified, for great x:
152 I_n(x) ~ e^x / sqrt( 2 PI x ) for x>=0.
155 // ----------------------------------------------------------------------------
157 double BesselI( double x
, sal_Int32 n
) throw( IllegalArgumentException
)
160 throw IllegalArgumentException();
162 double fResult
= 0.0;
163 if( fabs( x
) <= THRESHOLD
)
165 /* Start the iteration without TERM(n,0), which is set here.
167 TERM(n,0) = (x/2)^n / n!
169 double fTerm
= pow( x
/ 2.0, (double)n
) / Fak( n
);
170 sal_Int32 nK
= 1; // Start the iteration with k=1.
171 fResult
= fTerm
; // Start result with TERM(n,0).
173 const double fSqrX
= x
* x
/ 4.0;
177 /* Calculation of TERM(n,k) from TERM(n,k-1):
180 TERM(n,k) = --------------
183 (x/2)^2 (x/2)^(n+2(k-1))
184 = --------------------------
185 k (k-1)! (n+k) (n+k-1)!
187 (x/2)^2 (x/2)^(n+2(k-1))
188 = --------- * ------------------
189 k(n+k) (k-1)! (n+k-1)!
192 = -------- TERM(n,k-1)
195 fTerm
*= fSqrX
; // defined above as x^2/4
196 fTerm
/= (nK
* (nK
+ n
));
199 while( (fabs( fTerm
) > MAXEPSILON
) && (++nK
< MAXITER
) );
203 /* Approximation for the BESSEL function, first kind, modified:
205 I_n(x) ~ e^x / sqrt( 2 PI x ) for x>=0.
207 The BESSEL function I_n with n IN {0,2,4,...} is axially symmetric at
208 x=0, means I_n(x) = I_n(-x). Therefore the approximation for x<0 is:
210 I_n(x) = I_n(|x|) for x<0 and n IN {0,2,4,...}.
212 The BESSEL function I_n with n IN {1,3,5,...} is point-symmetric at
213 x=0, means I_n(x) = -I_n(-x). Therefore the approximation for x<0 is:
215 I_n(x) = -I_n(|x|) for x<0 and n IN {1,3,5,...}.
217 double fXAbs
= fabs( x
);
218 fResult
= exp( fXAbs
) / sqrt( f_2_PI
* fXAbs
);
219 if( (n
& 1) && (x
< 0.0) )
226 // ============================================================================
228 double Besselk0( double fNum
) throw( IllegalArgumentException
)
234 double fNum2
= fNum
* 0.5;
235 double y
= fNum2
* fNum2
;
237 fRet
= -log( fNum2
) * BesselI( fNum
, 0 ) +
238 ( -0.57721566 + y
* ( 0.42278420 + y
* ( 0.23069756 + y
* ( 0.3488590e-1 +
239 y
* ( 0.262698e-2 + y
* ( 0.10750e-3 + y
* 0.74e-5 ) ) ) ) ) );
243 double y
= 2.0 / fNum
;
245 fRet
= exp( -fNum
) / sqrt( fNum
) * ( 1.25331414 + y
* ( -0.7832358e-1 +
246 y
* ( 0.2189568e-1 + y
* ( -0.1062446e-1 + y
* ( 0.587872e-2 +
247 y
* ( -0.251540e-2 + y
* 0.53208e-3 ) ) ) ) ) );
254 double Besselk1( double fNum
) throw( IllegalArgumentException
)
260 double fNum2
= fNum
* 0.5;
261 double y
= fNum2
* fNum2
;
263 fRet
= log( fNum2
) * BesselI( fNum
, 1 ) +
264 ( 1.0 + y
* ( 0.15443144 + y
* ( -0.67278579 + y
* ( -0.18156897 + y
* ( -0.1919402e-1 +
265 y
* ( -0.110404e-2 + y
* ( -0.4686e-4 ) ) ) ) ) ) )
270 double y
= 2.0 / fNum
;
272 fRet
= exp( -fNum
) / sqrt( fNum
) * ( 1.25331414 + y
* ( 0.23498619 +
273 y
* ( -0.3655620e-1 + y
* ( 0.1504268e-1 + y
* ( -0.780353e-2 +
274 y
* ( 0.325614e-2 + y
* ( -0.68245e-3 ) ) ) ) ) ) );
281 double BesselK( double fNum
, sal_Int32 nOrder
) throw( IllegalArgumentException
)
285 case 0: return Besselk0( fNum
);
286 case 1: return Besselk1( fNum
);
291 double fTox
= 2.0 / fNum
;
292 double fBkm
= Besselk0( fNum
);
293 double fBk
= Besselk1( fNum
);
295 for( sal_Int32 n
= 1 ; n
< nOrder
; n
++ )
297 fBkp
= fBkm
+ double( n
) * fTox
* fBk
;
308 double Bessely0( double fNum
) throw( IllegalArgumentException
)
314 double y
= fNum
* fNum
;
316 double f1
= -2957821389.0 + y
* ( 7062834065.0 + y
* ( -512359803.6 +
317 y
* ( 10879881.29 + y
* ( -86327.92757 + y
* 228.4622733 ) ) ) );
319 double f2
= 40076544269.0 + y
* ( 745249964.8 + y
* ( 7189466.438 +
320 y
* ( 47447.26470 + y
* ( 226.1030244 + y
) ) ) );
322 fRet
= f1
/ f2
+ 0.636619772 * BesselJ( fNum
, 0 ) * log( fNum
);
326 double z
= 8.0 / fNum
;
328 double xx
= fNum
- 0.785398164;
330 double f1
= 1.0 + y
* ( -0.1098628627e-2 + y
* ( 0.2734510407e-4 +
331 y
* ( -0.2073370639e-5 + y
* 0.2093887211e-6 ) ) );
333 double f2
= -0.1562499995e-1 + y
* ( 0.1430488765e-3 +
334 y
* ( -0.6911147651e-5 + y
* ( 0.7621095161e-6 +
335 y
* ( -0.934945152e-7 ) ) ) );
337 fRet
= sqrt( 0.636619772 / fNum
) * ( sin( xx
) * f1
+ z
* cos( xx
) * f2
);
344 double Bessely1( double fNum
) throw( IllegalArgumentException
)
350 double y
= fNum
* fNum
;
352 double f1
= fNum
* ( -0.4900604943e13
+ y
* ( 0.1275274390e13
+
353 y
* ( -0.5153438139e11
+ y
* ( 0.7349264551e9
+
354 y
* ( -0.4237922726e7
+ y
* 0.8511937935e4
) ) ) ) );
356 double f2
= 0.2499580570e14
+ y
* ( 0.4244419664e12
+
357 y
* ( 0.3733650367e10
+ y
* ( 0.2245904002e8
+
358 y
* ( 0.1020426050e6
+ y
* ( 0.3549632885e3
+ y
) ) ) ) );
360 fRet
= f1
/ f2
+ 0.636619772 * ( BesselJ( fNum
, 1 ) * log( fNum
) - 1.0 / fNum
);
365 // #i12430# don't know the intention of this piece of code...
366 double z
= 8.0 / fNum
;
368 double xx
= fNum
- 2.356194491;
370 double f1
= 1.0 + y
* ( 0.183105e-2 + y
* ( -0.3516396496e-4 +
371 y
* ( 0.2457520174e-5 + y
* ( -0.240337019e6
) ) ) );
373 double f2
= 0.04687499995 + y
* ( -0.2002690873e-3 +
374 y
* ( 0.8449199096e-5 + y
* ( -0.88228987e-6 +
375 y
* 0.105787412e-6 ) ) );
377 fRet
= sqrt( 0.636619772 / fNum
) * ( sin( xx
) * f1
+ z
* cos( xx
) * f2
);
379 // #i12430# ...but this seems to work much better.
380 fRet
= sqrt( 0.636619772 / fNum
) * sin( fNum
- 2.356194491 );
387 double BesselY( double fNum
, sal_Int32 nOrder
) throw( IllegalArgumentException
)
391 case 0: return Bessely0( fNum
);
392 case 1: return Bessely1( fNum
);
397 double fTox
= 2.0 / fNum
;
398 double fBym
= Bessely0( fNum
);
399 double fBy
= Bessely1( fNum
);
401 for( sal_Int32 n
= 1 ; n
< nOrder
; n
++ )
403 fByp
= double( n
) * fTox
* fBy
- fBym
;
414 // ============================================================================
416 } // namespace analysis