xref: /AOO41X/main/scaddins/source/analysis/bessel.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir #include "bessel.hxx"
29*cdf0e10cSrcweir #include "analysishelper.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include <rtl/math.hxx>
32*cdf0e10cSrcweir 
33*cdf0e10cSrcweir using ::com::sun::star::lang::IllegalArgumentException;
34*cdf0e10cSrcweir using ::com::sun::star::sheet::NoConvergenceException;
35*cdf0e10cSrcweir 
36*cdf0e10cSrcweir namespace sca {
37*cdf0e10cSrcweir namespace analysis {
38*cdf0e10cSrcweir 
39*cdf0e10cSrcweir // ============================================================================
40*cdf0e10cSrcweir 
41*cdf0e10cSrcweir const double f_PI       = 3.1415926535897932385;
42*cdf0e10cSrcweir const double f_2_PI     = 2.0 * f_PI;
43*cdf0e10cSrcweir const double f_PI_DIV_2 = f_PI / 2.0;
44*cdf0e10cSrcweir const double f_PI_DIV_4 = f_PI / 4.0;
45*cdf0e10cSrcweir const double f_2_DIV_PI = 2.0 / f_PI;
46*cdf0e10cSrcweir 
47*cdf0e10cSrcweir const double THRESHOLD  = 30.0;     // Threshold for usage of approximation formula.
48*cdf0e10cSrcweir const double MAXEPSILON = 1e-10;    // Maximum epsilon for end of iteration.
49*cdf0e10cSrcweir const sal_Int32 MAXITER = 100;      // Maximum number of iterations.
50*cdf0e10cSrcweir 
51*cdf0e10cSrcweir // ============================================================================
52*cdf0e10cSrcweir // BESSEL J
53*cdf0e10cSrcweir // ============================================================================
54*cdf0e10cSrcweir 
55*cdf0e10cSrcweir /*  The BESSEL function, first kind, unmodified:
56*cdf0e10cSrcweir     The algorithm follows
57*cdf0e10cSrcweir     http://www.reference-global.com/isbn/978-3-11-020354-7
58*cdf0e10cSrcweir     Numerical Mathematics 1 / Numerische Mathematik 1,
59*cdf0e10cSrcweir     An algorithm-based introduction / Eine algorithmisch orientierte Einfuehrung
60*cdf0e10cSrcweir     Deuflhard, Peter; Hohmann, Andreas
61*cdf0e10cSrcweir     Berlin, New York (Walter de Gruyter) 2008
62*cdf0e10cSrcweir     4. ueberarb. u. erw. Aufl. 2008
63*cdf0e10cSrcweir     eBook ISBN: 978-3-11-020355-4
64*cdf0e10cSrcweir     Chapter 6.3.2 , algorithm 6.24
65*cdf0e10cSrcweir     The source is in German.
66*cdf0e10cSrcweir     The BesselJ-function is a special case of the adjoint summation with
67*cdf0e10cSrcweir     a_k = 2*(k-1)/x for k=1,...
68*cdf0e10cSrcweir     b_k = -1, for all k, directly substituted
69*cdf0e10cSrcweir     m_0=1, m_k=2 for k even, and m_k=0 for k odd, calculated on the fly
70*cdf0e10cSrcweir     alpha_k=1 for k=N and alpha_k=0 otherwise
71*cdf0e10cSrcweir */
72*cdf0e10cSrcweir 
73*cdf0e10cSrcweir // ----------------------------------------------------------------------------
74*cdf0e10cSrcweir 
75*cdf0e10cSrcweir double BesselJ( double x, sal_Int32 N ) throw (IllegalArgumentException, NoConvergenceException)
76*cdf0e10cSrcweir 
77*cdf0e10cSrcweir {
78*cdf0e10cSrcweir     if( N < 0 )
79*cdf0e10cSrcweir         throw IllegalArgumentException();
80*cdf0e10cSrcweir     if (x==0.0)
81*cdf0e10cSrcweir         return (N==0) ? 1.0 : 0.0;
82*cdf0e10cSrcweir 
83*cdf0e10cSrcweir     /*  The algorithm works only for x>0, therefore remember sign. BesselJ
84*cdf0e10cSrcweir         with integer order N is an even function for even N (means J(-x)=J(x))
85*cdf0e10cSrcweir         and an odd function for odd N (means J(-x)=-J(x)).*/
86*cdf0e10cSrcweir     double fSign = (N % 2 == 1 && x < 0) ? -1.0 : 1.0;
87*cdf0e10cSrcweir     double fX = fabs(x);
88*cdf0e10cSrcweir 
89*cdf0e10cSrcweir     const double fMaxIteration = 9000000.0; //experimental, for to return in < 3 seconds
90*cdf0e10cSrcweir     double fEstimateIteration = fX * 1.5 + N;
91*cdf0e10cSrcweir     bool bAsymptoticPossible = pow(fX,0.4) > N;
92*cdf0e10cSrcweir     if (fEstimateIteration > fMaxIteration)
93*cdf0e10cSrcweir     {
94*cdf0e10cSrcweir         if (bAsymptoticPossible)
95*cdf0e10cSrcweir             return fSign * sqrt(f_2_DIV_PI/fX)* cos(fX-N*f_PI_DIV_2-f_PI_DIV_4);
96*cdf0e10cSrcweir         else
97*cdf0e10cSrcweir             throw NoConvergenceException();
98*cdf0e10cSrcweir     }
99*cdf0e10cSrcweir 
100*cdf0e10cSrcweir     double epsilon = 1.0e-15; // relative error
101*cdf0e10cSrcweir     bool bHasfound = false;
102*cdf0e10cSrcweir     double k= 0.0;
103*cdf0e10cSrcweir     // e_{-1} = 0; e_0 = alpha_0 / b_2
104*cdf0e10cSrcweir     double  u ; // u_0 = e_0/f_0 = alpha_0/m_0 = alpha_0
105*cdf0e10cSrcweir 
106*cdf0e10cSrcweir     // first used with k=1
107*cdf0e10cSrcweir     double m_bar;         // m_bar_k = m_k * f_bar_{k-1}
108*cdf0e10cSrcweir     double g_bar;         // g_bar_k = m_bar_k - a_{k+1} + g_{k-1}
109*cdf0e10cSrcweir     double g_bar_delta_u; // g_bar_delta_u_k = f_bar_{k-1} * alpha_k
110*cdf0e10cSrcweir                           // - g_{k-1} * delta_u_{k-1} - m_bar_k * u_{k-1}
111*cdf0e10cSrcweir     // f_{-1} = 0.0; f_0 = m_0 / b_2 = 1/(-1) = -1
112*cdf0e10cSrcweir     double g = 0.0;       // g_0= f_{-1} / f_0 = 0/(-1) = 0
113*cdf0e10cSrcweir     double delta_u = 0.0; // dummy initialize, first used with * 0
114*cdf0e10cSrcweir     double f_bar = -1.0;  // f_bar_k = 1/f_k, but only used for k=0
115*cdf0e10cSrcweir 
116*cdf0e10cSrcweir     if (N==0)
117*cdf0e10cSrcweir     {
118*cdf0e10cSrcweir         //k=0; alpha_0 = 1.0
119*cdf0e10cSrcweir         u = 1.0; // u_0 = alpha_0
120*cdf0e10cSrcweir         // k = 1.0; at least one step is necessary
121*cdf0e10cSrcweir         // m_bar_k = m_k * f_bar_{k-1} ==> m_bar_1 = 0.0
122*cdf0e10cSrcweir         g_bar_delta_u = 0.0;    // alpha_k = 0.0, m_bar = 0.0; g= 0.0
123*cdf0e10cSrcweir         g_bar = - 2.0/fX;       // k = 1.0, g = 0.0
124*cdf0e10cSrcweir         delta_u = g_bar_delta_u / g_bar;
125*cdf0e10cSrcweir         u = u + delta_u ;       // u_k = u_{k-1} + delta_u_k
126*cdf0e10cSrcweir         g = -1.0 / g_bar;       // g_k=b_{k+2}/g_bar_k
127*cdf0e10cSrcweir         f_bar = f_bar * g;      // f_bar_k = f_bar_{k-1}* g_k
128*cdf0e10cSrcweir         k = 2.0;
129*cdf0e10cSrcweir         // From now on all alpha_k = 0.0 and k > N+1
130*cdf0e10cSrcweir     }
131*cdf0e10cSrcweir     else
132*cdf0e10cSrcweir     {   // N >= 1 and alpha_k = 0.0 for k<N
133*cdf0e10cSrcweir         u=0.0; // u_0 = alpha_0
134*cdf0e10cSrcweir         for (k =1.0; k<= N-1; k = k + 1.0)
135*cdf0e10cSrcweir         {
136*cdf0e10cSrcweir             m_bar=2.0 * fmod(k-1.0, 2.0) * f_bar;
137*cdf0e10cSrcweir             g_bar_delta_u = - g * delta_u - m_bar * u; // alpha_k = 0.0
138*cdf0e10cSrcweir             g_bar = m_bar - 2.0*k/fX + g;
139*cdf0e10cSrcweir             delta_u = g_bar_delta_u / g_bar;
140*cdf0e10cSrcweir             u = u + delta_u;
141*cdf0e10cSrcweir             g = -1.0/g_bar;
142*cdf0e10cSrcweir             f_bar=f_bar * g;
143*cdf0e10cSrcweir         }
144*cdf0e10cSrcweir         // Step alpha_N = 1.0
145*cdf0e10cSrcweir         m_bar=2.0 * fmod(k-1.0, 2.0) * f_bar;
146*cdf0e10cSrcweir         g_bar_delta_u = f_bar - g * delta_u - m_bar * u; // alpha_k = 1.0
147*cdf0e10cSrcweir         g_bar = m_bar - 2.0*k/fX + g;
148*cdf0e10cSrcweir         delta_u = g_bar_delta_u / g_bar;
149*cdf0e10cSrcweir         u = u + delta_u;
150*cdf0e10cSrcweir         g = -1.0/g_bar;
151*cdf0e10cSrcweir         f_bar = f_bar * g;
152*cdf0e10cSrcweir         k = k + 1.0;
153*cdf0e10cSrcweir     }
154*cdf0e10cSrcweir     // Loop until desired accuracy, always alpha_k = 0.0
155*cdf0e10cSrcweir     do
156*cdf0e10cSrcweir     {
157*cdf0e10cSrcweir         m_bar = 2.0 * fmod(k-1.0, 2.0) * f_bar;
158*cdf0e10cSrcweir         g_bar_delta_u = - g * delta_u - m_bar * u;
159*cdf0e10cSrcweir         g_bar = m_bar - 2.0*k/fX + g;
160*cdf0e10cSrcweir         delta_u = g_bar_delta_u / g_bar;
161*cdf0e10cSrcweir         u = u + delta_u;
162*cdf0e10cSrcweir         g = -1.0/g_bar;
163*cdf0e10cSrcweir         f_bar = f_bar * g;
164*cdf0e10cSrcweir         bHasfound = (fabs(delta_u)<=fabs(u)*epsilon);
165*cdf0e10cSrcweir         k = k + 1.0;
166*cdf0e10cSrcweir     }
167*cdf0e10cSrcweir     while (!bHasfound && k <= fMaxIteration);
168*cdf0e10cSrcweir     if (bHasfound)
169*cdf0e10cSrcweir         return u * fSign;
170*cdf0e10cSrcweir     else
171*cdf0e10cSrcweir         throw NoConvergenceException(); // unlikely to happen
172*cdf0e10cSrcweir }
173*cdf0e10cSrcweir 
174*cdf0e10cSrcweir // ============================================================================
175*cdf0e10cSrcweir // BESSEL I
176*cdf0e10cSrcweir // ============================================================================
177*cdf0e10cSrcweir 
178*cdf0e10cSrcweir /*  The BESSEL function, first kind, modified:
179*cdf0e10cSrcweir 
180*cdf0e10cSrcweir                      inf                                  (x/2)^(n+2k)
181*cdf0e10cSrcweir         I_n(x)  =  SUM   TERM(n,k)   with   TERM(n,k) := --------------
182*cdf0e10cSrcweir                      k=0                                   k! (n+k)!
183*cdf0e10cSrcweir 
184*cdf0e10cSrcweir     No asymptotic approximation used, see issue 43040.
185*cdf0e10cSrcweir  */
186*cdf0e10cSrcweir 
187*cdf0e10cSrcweir // ----------------------------------------------------------------------------
188*cdf0e10cSrcweir 
189*cdf0e10cSrcweir double BesselI( double x, sal_Int32 n ) throw( IllegalArgumentException, NoConvergenceException )
190*cdf0e10cSrcweir {
191*cdf0e10cSrcweir     const double fEpsilon = 1.0E-15;
192*cdf0e10cSrcweir     const sal_Int32 nMaxIteration = 2000;
193*cdf0e10cSrcweir     const double fXHalf = x / 2.0;
194*cdf0e10cSrcweir     if( n < 0 )
195*cdf0e10cSrcweir         throw IllegalArgumentException();
196*cdf0e10cSrcweir 
197*cdf0e10cSrcweir     double fResult = 0.0;
198*cdf0e10cSrcweir 
199*cdf0e10cSrcweir     /*  Start the iteration without TERM(n,0), which is set here.
200*cdf0e10cSrcweir 
201*cdf0e10cSrcweir             TERM(n,0) = (x/2)^n / n!
202*cdf0e10cSrcweir      */
203*cdf0e10cSrcweir     sal_Int32 nK = 0;
204*cdf0e10cSrcweir     double fTerm = 1.0;
205*cdf0e10cSrcweir     // avoid overflow in Fak(n)
206*cdf0e10cSrcweir     for( nK = 1; nK <= n; ++nK )
207*cdf0e10cSrcweir     {
208*cdf0e10cSrcweir         fTerm = fTerm / static_cast< double >( nK ) * fXHalf;
209*cdf0e10cSrcweir     }
210*cdf0e10cSrcweir     fResult = fTerm;    // Start result with TERM(n,0).
211*cdf0e10cSrcweir     if( fTerm != 0.0 )
212*cdf0e10cSrcweir     {
213*cdf0e10cSrcweir         nK = 1;
214*cdf0e10cSrcweir         do
215*cdf0e10cSrcweir         {
216*cdf0e10cSrcweir             /*  Calculation of TERM(n,k) from TERM(n,k-1):
217*cdf0e10cSrcweir 
218*cdf0e10cSrcweir                                    (x/2)^(n+2k)
219*cdf0e10cSrcweir                     TERM(n,k)  =  --------------
220*cdf0e10cSrcweir                                     k! (n+k)!
221*cdf0e10cSrcweir 
222*cdf0e10cSrcweir                                    (x/2)^2 (x/2)^(n+2(k-1))
223*cdf0e10cSrcweir                                =  --------------------------
224*cdf0e10cSrcweir                                    k (k-1)! (n+k) (n+k-1)!
225*cdf0e10cSrcweir 
226*cdf0e10cSrcweir                                    (x/2)^2     (x/2)^(n+2(k-1))
227*cdf0e10cSrcweir                                =  --------- * ------------------
228*cdf0e10cSrcweir                                    k(n+k)      (k-1)! (n+k-1)!
229*cdf0e10cSrcweir 
230*cdf0e10cSrcweir                                    x^2/4
231*cdf0e10cSrcweir                                =  -------- TERM(n,k-1)
232*cdf0e10cSrcweir                                    k(n+k)
233*cdf0e10cSrcweir             */
234*cdf0e10cSrcweir         fTerm = fTerm * fXHalf / static_cast<double>(nK) * fXHalf / static_cast<double>(nK+n);
235*cdf0e10cSrcweir         fResult += fTerm;
236*cdf0e10cSrcweir         nK++;
237*cdf0e10cSrcweir         }
238*cdf0e10cSrcweir         while( (fabs( fTerm ) > fabs(fResult) * fEpsilon) && (nK < nMaxIteration) );
239*cdf0e10cSrcweir 
240*cdf0e10cSrcweir     }
241*cdf0e10cSrcweir     return fResult;
242*cdf0e10cSrcweir }
243*cdf0e10cSrcweir 
244*cdf0e10cSrcweir 
245*cdf0e10cSrcweir // ============================================================================
246*cdf0e10cSrcweir 
247*cdf0e10cSrcweir double Besselk0( double fNum ) throw( IllegalArgumentException, NoConvergenceException )
248*cdf0e10cSrcweir {
249*cdf0e10cSrcweir 	double	fRet;
250*cdf0e10cSrcweir 
251*cdf0e10cSrcweir 	if( fNum <= 2.0 )
252*cdf0e10cSrcweir 	{
253*cdf0e10cSrcweir 		double	fNum2 = fNum * 0.5;
254*cdf0e10cSrcweir 		double	y = fNum2 * fNum2;
255*cdf0e10cSrcweir 
256*cdf0e10cSrcweir         fRet = -log( fNum2 ) * BesselI( fNum, 0 ) +
257*cdf0e10cSrcweir 				( -0.57721566 + y * ( 0.42278420 + y * ( 0.23069756 + y * ( 0.3488590e-1 +
258*cdf0e10cSrcweir 					y * ( 0.262698e-2 + y * ( 0.10750e-3 + y * 0.74e-5 ) ) ) ) ) );
259*cdf0e10cSrcweir 	}
260*cdf0e10cSrcweir 	else
261*cdf0e10cSrcweir 	{
262*cdf0e10cSrcweir 		double	y = 2.0 / fNum;
263*cdf0e10cSrcweir 
264*cdf0e10cSrcweir 		fRet = exp( -fNum ) / sqrt( fNum ) * ( 1.25331414 + y * ( -0.7832358e-1 +
265*cdf0e10cSrcweir 				y * ( 0.2189568e-1 + y * ( -0.1062446e-1 + y * ( 0.587872e-2 +
266*cdf0e10cSrcweir 				y * ( -0.251540e-2 + y * 0.53208e-3 ) ) ) ) ) );
267*cdf0e10cSrcweir 	}
268*cdf0e10cSrcweir 
269*cdf0e10cSrcweir 	return fRet;
270*cdf0e10cSrcweir }
271*cdf0e10cSrcweir 
272*cdf0e10cSrcweir 
273*cdf0e10cSrcweir double Besselk1( double fNum ) throw( IllegalArgumentException, NoConvergenceException )
274*cdf0e10cSrcweir {
275*cdf0e10cSrcweir 	double	fRet;
276*cdf0e10cSrcweir 
277*cdf0e10cSrcweir 	if( fNum <= 2.0 )
278*cdf0e10cSrcweir 	{
279*cdf0e10cSrcweir 		double	fNum2 = fNum * 0.5;
280*cdf0e10cSrcweir 		double	y = fNum2 * fNum2;
281*cdf0e10cSrcweir 
282*cdf0e10cSrcweir         fRet = log( fNum2 ) * BesselI( fNum, 1 ) +
283*cdf0e10cSrcweir 				( 1.0 + y * ( 0.15443144 + y * ( -0.67278579 + y * ( -0.18156897 + y * ( -0.1919402e-1 +
284*cdf0e10cSrcweir 					y * ( -0.110404e-2 + y * ( -0.4686e-4 ) ) ) ) ) ) )
285*cdf0e10cSrcweir 				/ fNum;
286*cdf0e10cSrcweir 	}
287*cdf0e10cSrcweir 	else
288*cdf0e10cSrcweir 	{
289*cdf0e10cSrcweir 		double	y = 2.0 / fNum;
290*cdf0e10cSrcweir 
291*cdf0e10cSrcweir 		fRet = exp( -fNum ) / sqrt( fNum ) * ( 1.25331414 + y * ( 0.23498619 +
292*cdf0e10cSrcweir 				y * ( -0.3655620e-1 + y * ( 0.1504268e-1 + y * ( -0.780353e-2 +
293*cdf0e10cSrcweir 				y * ( 0.325614e-2 + y * ( -0.68245e-3 ) ) ) ) ) ) );
294*cdf0e10cSrcweir 	}
295*cdf0e10cSrcweir 
296*cdf0e10cSrcweir 	return fRet;
297*cdf0e10cSrcweir }
298*cdf0e10cSrcweir 
299*cdf0e10cSrcweir 
300*cdf0e10cSrcweir double BesselK( double fNum, sal_Int32 nOrder ) throw( IllegalArgumentException, NoConvergenceException )
301*cdf0e10cSrcweir {
302*cdf0e10cSrcweir 	switch( nOrder )
303*cdf0e10cSrcweir 	{
304*cdf0e10cSrcweir 		case 0:		return Besselk0( fNum );
305*cdf0e10cSrcweir 		case 1:		return Besselk1( fNum );
306*cdf0e10cSrcweir 		default:
307*cdf0e10cSrcweir 		{
308*cdf0e10cSrcweir 			double		fBkp;
309*cdf0e10cSrcweir 
310*cdf0e10cSrcweir 			double		fTox = 2.0 / fNum;
311*cdf0e10cSrcweir 			double		fBkm = Besselk0( fNum );
312*cdf0e10cSrcweir 			double		fBk = Besselk1( fNum );
313*cdf0e10cSrcweir 
314*cdf0e10cSrcweir 			for( sal_Int32 n = 1 ; n < nOrder ; n++ )
315*cdf0e10cSrcweir 			{
316*cdf0e10cSrcweir 				fBkp = fBkm + double( n ) * fTox * fBk;
317*cdf0e10cSrcweir 				fBkm = fBk;
318*cdf0e10cSrcweir 				fBk = fBkp;
319*cdf0e10cSrcweir 			}
320*cdf0e10cSrcweir 
321*cdf0e10cSrcweir 			return fBk;
322*cdf0e10cSrcweir 		}
323*cdf0e10cSrcweir 	}
324*cdf0e10cSrcweir }
325*cdf0e10cSrcweir 
326*cdf0e10cSrcweir // ============================================================================
327*cdf0e10cSrcweir // BESSEL Y
328*cdf0e10cSrcweir // ============================================================================
329*cdf0e10cSrcweir 
330*cdf0e10cSrcweir /*  The BESSEL function, second kind, unmodified:
331*cdf0e10cSrcweir     The algorithm for order 0 and for order 1 follows
332*cdf0e10cSrcweir     http://www.reference-global.com/isbn/978-3-11-020354-7
333*cdf0e10cSrcweir     Numerical Mathematics 1 / Numerische Mathematik 1,
334*cdf0e10cSrcweir     An algorithm-based introduction / Eine algorithmisch orientierte Einfuehrung
335*cdf0e10cSrcweir     Deuflhard, Peter; Hohmann, Andreas
336*cdf0e10cSrcweir     Berlin, New York (Walter de Gruyter) 2008
337*cdf0e10cSrcweir     4. ueberarb. u. erw. Aufl. 2008
338*cdf0e10cSrcweir     eBook ISBN: 978-3-11-020355-4
339*cdf0e10cSrcweir     Chapter 6.3.2 , algorithm 6.24
340*cdf0e10cSrcweir     The source is in German.
341*cdf0e10cSrcweir     See #i31656# for a commented version of the implementation, attachment #desc6
342*cdf0e10cSrcweir     http://www.openoffice.org/nonav/issues/showattachment.cgi/63609/Comments%20to%20the%20implementation%20of%20the%20Bessel%20functions.odt
343*cdf0e10cSrcweir */
344*cdf0e10cSrcweir 
345*cdf0e10cSrcweir double Bessely0( double fX ) throw( IllegalArgumentException, NoConvergenceException )
346*cdf0e10cSrcweir {
347*cdf0e10cSrcweir     if (fX <= 0)
348*cdf0e10cSrcweir         throw IllegalArgumentException();
349*cdf0e10cSrcweir     const double fMaxIteration = 9000000.0; // should not be reached
350*cdf0e10cSrcweir     if (fX > 5.0e+6) // iteration is not considerable better then approximation
351*cdf0e10cSrcweir         return sqrt(1/f_PI/fX)
352*cdf0e10cSrcweir                 *(rtl::math::sin(fX)-rtl::math::cos(fX));
353*cdf0e10cSrcweir     const double epsilon = 1.0e-15;
354*cdf0e10cSrcweir     const double EulerGamma = 0.57721566490153286060;
355*cdf0e10cSrcweir     double alpha = log(fX/2.0)+EulerGamma;
356*cdf0e10cSrcweir     double u = alpha;
357*cdf0e10cSrcweir 
358*cdf0e10cSrcweir     double k = 1.0;
359*cdf0e10cSrcweir     double m_bar = 0.0;
360*cdf0e10cSrcweir     double g_bar_delta_u = 0.0;
361*cdf0e10cSrcweir     double g_bar = -2.0 / fX;
362*cdf0e10cSrcweir     double delta_u = g_bar_delta_u / g_bar;
363*cdf0e10cSrcweir     double g = -1.0/g_bar;
364*cdf0e10cSrcweir     double f_bar = -1 * g;
365*cdf0e10cSrcweir 
366*cdf0e10cSrcweir     double sign_alpha = 1.0;
367*cdf0e10cSrcweir     double km1mod2;
368*cdf0e10cSrcweir     bool bHasFound = false;
369*cdf0e10cSrcweir     k = k + 1;
370*cdf0e10cSrcweir     do
371*cdf0e10cSrcweir     {
372*cdf0e10cSrcweir         km1mod2 = fmod(k-1.0,2.0);
373*cdf0e10cSrcweir         m_bar=(2.0*km1mod2) * f_bar;
374*cdf0e10cSrcweir         if (km1mod2 == 0.0)
375*cdf0e10cSrcweir             alpha = 0.0;
376*cdf0e10cSrcweir         else
377*cdf0e10cSrcweir         {
378*cdf0e10cSrcweir            alpha = sign_alpha * (4.0/k);
379*cdf0e10cSrcweir            sign_alpha = -sign_alpha;
380*cdf0e10cSrcweir         }
381*cdf0e10cSrcweir         g_bar_delta_u = f_bar * alpha - g * delta_u - m_bar * u;
382*cdf0e10cSrcweir         g_bar = m_bar - (2.0*k)/fX + g;
383*cdf0e10cSrcweir         delta_u = g_bar_delta_u / g_bar;
384*cdf0e10cSrcweir         u = u+delta_u;
385*cdf0e10cSrcweir         g = -1.0 / g_bar;
386*cdf0e10cSrcweir         f_bar = f_bar*g;
387*cdf0e10cSrcweir         bHasFound = (fabs(delta_u)<=fabs(u)*epsilon);
388*cdf0e10cSrcweir         k=k+1;
389*cdf0e10cSrcweir     }
390*cdf0e10cSrcweir     while (!bHasFound && k<fMaxIteration);
391*cdf0e10cSrcweir     if (bHasFound)
392*cdf0e10cSrcweir         return u*f_2_DIV_PI;
393*cdf0e10cSrcweir     else
394*cdf0e10cSrcweir         throw NoConvergenceException(); // not likely to happen
395*cdf0e10cSrcweir }
396*cdf0e10cSrcweir 
397*cdf0e10cSrcweir // See #i31656# for a commented version of this implementation, attachment #desc6
398*cdf0e10cSrcweir // http://www.openoffice.org/nonav/issues/showattachment.cgi/63609/Comments%20to%20the%20implementation%20of%20the%20Bessel%20functions.odt
399*cdf0e10cSrcweir double Bessely1( double fX ) throw( IllegalArgumentException, NoConvergenceException )
400*cdf0e10cSrcweir {
401*cdf0e10cSrcweir     if (fX <= 0)
402*cdf0e10cSrcweir         throw IllegalArgumentException();
403*cdf0e10cSrcweir     const double fMaxIteration = 9000000.0; // should not be reached
404*cdf0e10cSrcweir     if (fX > 5.0e+6) // iteration is not considerable better then approximation
405*cdf0e10cSrcweir         return - sqrt(1/f_PI/fX)
406*cdf0e10cSrcweir                 *(rtl::math::sin(fX)+rtl::math::cos(fX));
407*cdf0e10cSrcweir     const double epsilon = 1.0e-15;
408*cdf0e10cSrcweir     const double EulerGamma = 0.57721566490153286060;
409*cdf0e10cSrcweir     double alpha = 1.0/fX;
410*cdf0e10cSrcweir     double f_bar = -1.0;
411*cdf0e10cSrcweir     double g = 0.0;
412*cdf0e10cSrcweir     double u = alpha;
413*cdf0e10cSrcweir     double k = 1.0;
414*cdf0e10cSrcweir     double m_bar = 0.0;
415*cdf0e10cSrcweir     alpha = 1.0 - EulerGamma - log(fX/2.0);
416*cdf0e10cSrcweir     double g_bar_delta_u = -alpha;
417*cdf0e10cSrcweir     double g_bar = -2.0 / fX;
418*cdf0e10cSrcweir     double delta_u = g_bar_delta_u / g_bar;
419*cdf0e10cSrcweir     u = u + delta_u;
420*cdf0e10cSrcweir     g = -1.0/g_bar;
421*cdf0e10cSrcweir     f_bar = f_bar * g;
422*cdf0e10cSrcweir     double sign_alpha = -1.0;
423*cdf0e10cSrcweir     double km1mod2; //will be (k-1) mod 2
424*cdf0e10cSrcweir     double q; // will be (k-1) div 2
425*cdf0e10cSrcweir     bool bHasFound = false;
426*cdf0e10cSrcweir     k = k + 1.0;
427*cdf0e10cSrcweir     do
428*cdf0e10cSrcweir     {
429*cdf0e10cSrcweir         km1mod2 = fmod(k-1.0,2.0);
430*cdf0e10cSrcweir         m_bar=(2.0*km1mod2) * f_bar;
431*cdf0e10cSrcweir         q = (k-1.0)/2.0;
432*cdf0e10cSrcweir         if (km1mod2 == 0.0) // k is odd
433*cdf0e10cSrcweir         {
434*cdf0e10cSrcweir            alpha = sign_alpha * (1.0/q + 1.0/(q+1.0));
435*cdf0e10cSrcweir            sign_alpha = -sign_alpha;
436*cdf0e10cSrcweir         }
437*cdf0e10cSrcweir         else
438*cdf0e10cSrcweir             alpha = 0.0;
439*cdf0e10cSrcweir         g_bar_delta_u = f_bar * alpha - g * delta_u - m_bar * u;
440*cdf0e10cSrcweir         g_bar = m_bar - (2.0*k)/fX + g;
441*cdf0e10cSrcweir         delta_u = g_bar_delta_u / g_bar;
442*cdf0e10cSrcweir         u = u+delta_u;
443*cdf0e10cSrcweir         g = -1.0 / g_bar;
444*cdf0e10cSrcweir         f_bar = f_bar*g;
445*cdf0e10cSrcweir         bHasFound = (fabs(delta_u)<=fabs(u)*epsilon);
446*cdf0e10cSrcweir         k=k+1;
447*cdf0e10cSrcweir     }
448*cdf0e10cSrcweir     while (!bHasFound && k<fMaxIteration);
449*cdf0e10cSrcweir     if (bHasFound)
450*cdf0e10cSrcweir         return -u*2.0/f_PI;
451*cdf0e10cSrcweir     else
452*cdf0e10cSrcweir         throw NoConvergenceException();
453*cdf0e10cSrcweir }
454*cdf0e10cSrcweir 
455*cdf0e10cSrcweir double BesselY( double fNum, sal_Int32 nOrder ) throw( IllegalArgumentException, NoConvergenceException )
456*cdf0e10cSrcweir {
457*cdf0e10cSrcweir     switch( nOrder )
458*cdf0e10cSrcweir     {
459*cdf0e10cSrcweir         case 0:     return Bessely0( fNum );
460*cdf0e10cSrcweir         case 1:     return Bessely1( fNum );
461*cdf0e10cSrcweir         default:
462*cdf0e10cSrcweir         {
463*cdf0e10cSrcweir             double      fByp;
464*cdf0e10cSrcweir 
465*cdf0e10cSrcweir             double      fTox = 2.0 / fNum;
466*cdf0e10cSrcweir             double      fBym = Bessely0( fNum );
467*cdf0e10cSrcweir             double      fBy = Bessely1( fNum );
468*cdf0e10cSrcweir 
469*cdf0e10cSrcweir             for( sal_Int32 n = 1 ; n < nOrder ; n++ )
470*cdf0e10cSrcweir             {
471*cdf0e10cSrcweir                 fByp = double( n ) * fTox * fBy - fBym;
472*cdf0e10cSrcweir                 fBym = fBy;
473*cdf0e10cSrcweir                 fBy = fByp;
474*cdf0e10cSrcweir             }
475*cdf0e10cSrcweir 
476*cdf0e10cSrcweir             return fBy;
477*cdf0e10cSrcweir         }
478*cdf0e10cSrcweir     }
479*cdf0e10cSrcweir }
480*cdf0e10cSrcweir 
481*cdf0e10cSrcweir // ============================================================================
482*cdf0e10cSrcweir 
483*cdf0e10cSrcweir } // namespace analysis
484*cdf0e10cSrcweir } // namespace sca
485*cdf0e10cSrcweir 
486