Update ooo320-m1
[ooovba.git] / scaddins / source / analysis / bessel.cxx
blobe354695d98ab7492c14a3e3878645bfce3baef46
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: bessel.cxx,v $
10 * $Revision: 1.6 $
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 ************************************************************************/
31 #include "bessel.hxx"
32 #include "analysishelper.hxx"
34 #include <rtl/math.hxx>
36 using ::com::sun::star::lang::IllegalArgumentException;
38 namespace sca {
39 namespace analysis {
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 // ============================================================================
55 // BESSEL J
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) := ---------------------
62 k=0 k! (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 )
73 if( n < 0 )
74 throw IllegalArgumentException();
76 double fResult = 0.0;
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):
93 (-1)^k (x/2)^(n+2k)
94 TERM(n,k) = ---------------------
95 k! (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)!
105 -(x^2/4)
106 = ---------- TERM(n,k-1)
107 k(n+k)
109 fTerm *= fSqrX; // defined above as -(x^2/4)
110 fTerm /= (nK * (nK + n));
111 fResult += fTerm;
113 while( (fabs( fTerm ) > MAXEPSILON) && (++nK < MAXITER) );
115 else
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) )
134 fResult = -fResult;
136 return fResult;
140 // ============================================================================
141 // BESSEL I
142 // ============================================================================
144 /* The BESSEL function, first kind, modified:
146 inf (x/2)^(n+2k)
147 I_n(x) = SUM TERM(n,k) with TERM(n,k) := --------------
148 k=0 k! (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 )
159 if( n < 0 )
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):
179 (x/2)^(n+2k)
180 TERM(n,k) = --------------
181 k! (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)!
191 x^2/4
192 = -------- TERM(n,k-1)
193 k(n+k)
195 fTerm *= fSqrX; // defined above as x^2/4
196 fTerm /= (nK * (nK + n));
197 fResult += fTerm;
199 while( (fabs( fTerm ) > MAXEPSILON) && (++nK < MAXITER) );
201 else
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) )
220 fResult = -fResult;
222 return fResult;
226 // ============================================================================
228 double Besselk0( double fNum ) throw( IllegalArgumentException )
230 double fRet;
232 if( fNum <= 2.0 )
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 ) ) ) ) ) );
241 else
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 ) ) ) ) ) );
250 return fRet;
254 double Besselk1( double fNum ) throw( IllegalArgumentException )
256 double fRet;
258 if( fNum <= 2.0 )
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 ) ) ) ) ) ) )
266 / fNum;
268 else
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 ) ) ) ) ) ) );
277 return fRet;
281 double BesselK( double fNum, sal_Int32 nOrder ) throw( IllegalArgumentException )
283 switch( nOrder )
285 case 0: return Besselk0( fNum );
286 case 1: return Besselk1( fNum );
287 default:
289 double fBkp;
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;
298 fBkm = fBk;
299 fBk = fBkp;
302 return fBk;
308 double Bessely0( double fNum ) throw( IllegalArgumentException )
310 double fRet;
312 if( fNum < 8.0 )
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 );
324 else
326 double z = 8.0 / fNum;
327 double y = z * z;
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 );
340 return fRet;
344 double Bessely1( double fNum ) throw( IllegalArgumentException )
346 double fRet;
348 if( fNum < 8.0 )
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 );
362 else
364 #if 0
365 // #i12430# don't know the intention of this piece of code...
366 double z = 8.0 / fNum;
367 double y = z * z;
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 );
378 #endif
379 // #i12430# ...but this seems to work much better.
380 fRet = sqrt( 0.636619772 / fNum ) * sin( fNum - 2.356194491 );
383 return fRet;
387 double BesselY( double fNum, sal_Int32 nOrder ) throw( IllegalArgumentException )
389 switch( nOrder )
391 case 0: return Bessely0( fNum );
392 case 1: return Bessely1( fNum );
393 default:
395 double fByp;
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;
404 fBym = fBy;
405 fBy = fByp;
408 return fBy;
414 // ============================================================================
416 } // namespace analysis
417 } // namespace sca