17
12/7/2011 1 Titus Beu 2011 Titus Beu University “Babes-Bolyai” Department of Theoretical and Computational Physics Cluj-Napoca, Romania 6. 6. Evaluation of functions Evaluation of functions Titus Beu 2011 Bibliography Evaluation of polynomials. Horner's scheme Evaluation of analytical functions Continued fractions Orthogonal polynomials Spherical harmonics. Associated Legendre functions Spherical Bessel functions

Metode numerice in C - Titus Beu

Embed Size (px)

DESCRIPTION

Calcul polinomial

Citation preview

12/7/2011

1

Titus Beu 2011

Titus BeuUniversity “Babes-Bolyai”Department of Theoretical and Computational PhysicsCluj-Napoca, Romania

6. 6. Evaluation of functionsEvaluation of functions

Titus Beu 2011

Bibliography

Evaluation of polynomials. Horner's scheme

Evaluation of analytical functions

Continued fractions

Orthogonal polynomials

Spherical harmonics. Associated Legendre functions

Spherical Bessel functions

12/7/2011

2

Titus Beu 2011

Abramowitz, M. and Stegun, I., Handbook of Mathematical Functions (Dover Publications, New York, 1972).

Knuth, D.E. , The Art of Computer Programming, vol. 2: Seminumerical Algorithms (Addison-Wesley, Reading, MA, 1981).

Acton, F.S. , Numerical Methods That Work (Mathematical Association of America, Washington, 1990).

Beu, T. A., Numerical Calculus in C, Third Edition(MicroInformatica Publishing House, Cluj-Napoca, 2004).

Titus Beu 2011

Polynomial of degree n:

Value for x = ξ:

Horner's scheme:

Any rational fraction, R(x) = P(x)/Q(x), can be evaluated using Horner's scheme.

1

0 1 1( )

n n

n nP x a x a x a x a−

−= + + + +�

0 1 2 1( ) ( (( ) ) )n nP a a a a aξ ξ ξ ξ ξ−= + + + + +� �

0 0

1, 1, 2, ,

( )

i i i

n

p a

p p a i n

P p

ξ

ξ

=

= + =

=

12/7/2011

3

Titus Beu 2011

//===========================================================================

float Polynomial(float x, float a[], int n)//---------------------------------------------------------------------------

Evaluate polynomial of order n with real coefficients a[] at point x//---------------------------------------------------------------------------

{float p;

int i;

p = a[0];for (i=1; i<=n; i++) p = p*x + a[i];

return p;}

//===========================================================================

float Polynomial(float x, float a[], int n)//---------------------------------------------------------------------------

Evaluate polynomial of order n with real coefficients a[] at point x//---------------------------------------------------------------------------

{float p;

int i;

p = a[0];for (i=1; i<=n; i++) p = p*x + a[i];

return p;}

Titus Beu 2011

f(x) is called analytical in ξ if in some neighbourhood |x – ξ| < R:

Taylor polynomial (partial sum) of order n:

Error estimates (absolute and relative):

Convergence criterion for the relative error estimate:

fx = fξ +f ′ξ

1!x − ξ +

f ′′ξ2!

x − ξ2 + ⋯

( )

0 0

( )( ) ( ) ( )

!

in ni

n i

i i

fF x x t x

i

ξξ

= =

= − =∑ ∑

( ) ( ) ( )| ( ) |,

( )

n n n

n

n

t xt x

F xδ∆ = =

( )or | ( ) | | ( ) |

( )

nn n

n

t xt x F x

F xε ε≤ ≤

12/7/2011

4

Titus Beu 2011

Example – exponential functions:

Taylor polynomial (partial sum) of order n:

Recurrent scheme:

Convergence criterion for the relative error estimate:

2

0

12! !

ix

i

x xe x

i

=

= + + + =∑�

0

( ) ( ), ( )!

in

n i i

i

xF x t x t x

i=

= =∑

t0 = 1, F0 = 1

t i = x/i t i−1 , F i = F i−1 + t i, i = 1,2,… ,n,…

or | | | |nn n

n

tt F

Fε ε≤ ≤

Titus Beu 2011

//===========================================================================

float Exp0(float x)//---------------------------------------------------------------------------

Evaluates exponential for argument x from its series expansion//---------------------------------------------------------------------------

{const float eps = 1e-6;

float f, t;int i;

i = 1;

f = t = 1.0;while (fabs(t/f) > eps) {

t *= x/(i++);f += t;

}return f;

}

//===========================================================================

float Exp0(float x)//---------------------------------------------------------------------------

Evaluates exponential for argument x from its series expansion//---------------------------------------------------------------------------

{const float eps = 1e-6;

float f, t;int i;

i = 1;

f = t = 1.0;while (fabs(t/f) > eps) {

t *= x/(i++);f += t;

}return f;

}

12/7/2011

5

Titus Beu 2011

//===========================================================================

float Exp(float x)//---------------------------------------------------------------------------

Evaluates exponential for argument x from its series expansion//---------------------------------------------------------------------------

{const float eps = 1e-6;

float absx, f, t;int i;

i = 1;

f = t = 1.0;absx = fabs(x);

while (fabs(t/f) > eps) {t *= absx/(i++);

f += t;}

return (x >= 0.0 ? f : 1.0/f);}

//===========================================================================

float Exp(float x)//---------------------------------------------------------------------------

Evaluates exponential for argument x from its series expansion//---------------------------------------------------------------------------

{const float eps = 1e-6;

float absx, f, t;int i;

i = 1;

f = t = 1.0;absx = fabs(x);

while (fabs(t/f) > eps) {t *= absx/(i++);

f += t;}

return (x >= 0.0 ? f : 1.0/f);}

x < 0 – alternating positive and negative terms – accumulation of errors by subtraction

Convenient definition:

| |

| |

if 0

1/ if 0

x

x

x

e xe

e x

≥=

<

Titus Beu 2011

Continued fraction – expression of the form:

where ai and bi can be real numbers, complex numbers or functions.

Convergents of a continued fraction:

A continued fraction is convergent if the limit exists:

Continued fractions are generally more rapidly converging than other infinite representations

a0 +b1

a1 +b2

a2 + ⋯

≡ a0 ;b1

a1,

b2

a2,… ,

bi

ai,…

R1 = a0 +b1

a1, R2 = a0 +

b1

a1 +b2

a2

,…

limi

iA R

→∞=

12/7/2011

6

Titus Beu 2011

Law of formation of convergents

The convergents of a continued fraction can be expressed as fractions

with the numerator and denominator given by

and the starting values:

1 2

1 2

i i i i i

i i i i i

P a P b P

Q a Q bQ

− −

− −

= +

= +

0 0 1

0 1

, 1

1, 0

P a P

Q Q

= =

= =

, 1, 2,3,ii

i

PR i

Q= = …

Titus Beu 2011

Proof (by induction)

For i = 1:

As per hypothesis:

Ri+1 results from Ri by replacing ai with ai + bi+1/ai+1

R1 =P1

Q1

=a1P0 + b1P−1

a1Q0 + b1Q−1

= a0 +b1

a1

1 2

1 2

i i i i ii

i i i i i

P a P b PR

Q a Q b Q

− −

− −

+= =

+

Ri+1 =ai+1P i + b i+1P i−1

ai+1Qi + b i+1Qi−1

=P i+1

Qi+1

12/7/2011

7

Titus Beu 2011

Example – tangent function

Continued fraction representation:

Coefficients:

Initial values:

Recurrence relations:

2 2 2

tan 0; , , , , ,1 3 5 2 1

x x x xx

i

− − −=

− … …

a0 = 0, a1 = 1, ai = ai−1 + 2

b1 = x, bi = −x 2 , i = 2,3,…

0 1 1

2

0 1

0, , 1

1, 1,

P P x a

Q Q b x

= = =

= = = −

1

1 2

1 2

2, 2,3,i i

i i i i

i i i i

a a i

P a P bP

Q a Q bQ

− −

− −

= + =

= +

= +

Titus Beu 2011

//===========================================================================

float Tan(float x)//---------------------------------------------------------------------------

Evaluates the tangent from its continued fraction representation//---------------------------------------------------------------------------

{const float eps = 1e-6;

float a, b, p, pm, pp, q, qm, qp;

if (x == 0.0) return 0.0;pm = 0.0; p = x ; a = 1.0;

qm = 1.0; q = 1.0; b = -x*x;while (fabs(1.0 - (pm*q)/(p*qm)) > eps) {

a += 2.0;pp = a*p + b*pm; pm = p; p = pp;

qp = a*q + b*qm; qm = q; q = qp;}

return p/q;}

//===========================================================================

float Tan(float x)//---------------------------------------------------------------------------

Evaluates the tangent from its continued fraction representation//---------------------------------------------------------------------------

{const float eps = 1e-6;

float a, b, p, pm, pp, q, qm, qp;

if (x == 0.0) return 0.0;pm = 0.0; p = x ; a = 1.0;

qm = 1.0; q = 1.0; b = -x*x;while (fabs(1.0 - (pm*q)/(p*qm)) > eps) {

a += 2.0;pp = a*p + b*pm; pm = p; p = pp;

qp = a*q + b*qm; qm = q; q = qp;}

return p/q;}

Example – tangent function

Convergence criterion:

1 1

1

1 1i i i

i i i

R P Q

R Q Pε− −

− = − ≤

12/7/2011

8

Titus Beu 2011

{fn(x)} – orthogonal system on [a,b] with respect to the weight function w(x) > 0 if

General relations

Second order differential equation:

Recurrence relation with respect to the order:

Functional form for first derivative:

( ) ( ) ( ) ( , 0,1, 2, )b

n m n nmaw x f x f x dx N n mδ= =∫ …

2 1( ) ( ) ( ) ( ) ( ) 0n n n ng x f x g x f x h f x

′′ ′+ + =

1 2( ) ( ) ( ) ( )n n n n n n na f x b c x f x d f x− −= + −

2 1 0 1( ) ( ) ( ) ( ) ( ) ( )n n ng x f x g x f x g x f x

′−= +

Titus Beu 2011

Name fn(x) a b w(x) Nn

Chebyshev

1st kind

Tn(x) −1 1 (1 − x2)−1/2 π if n = 0

π/2 if n ≠ 0

Legendre Pn(x) −1 1 1 2/(2n + 1)

Laguerre Ln(x) 0 ∞ e−x 1

Hermite Hn(x) −∞ ∞ e−x2 π1/22nn!

fn(x) an bn cn dn f0(x) f1(x)

Tn(x) 1 0 2 1 1 x

Pn(x) n 0 2n − 1 n − 1 1 x

Ln(x) n 2n − 1 −1 n − 1 1 1 − x

Hn(x) 1 0 2 2(n − 1) 1 2x

12/7/2011

9

Titus Beu 2011

fn(x) g2(x) g1(x) g0(x)

Tn(x) 1 − x2 −nx n

Pn(x) 1 − x2 −nx n

Ln(x) x n −n

Hn(x) 1 0 2n

Evaluation of orthogonal polynomial fn(x) for x = ξ

1. One evaluates f0(ξ) and f1(ξ)

2. One applies for i = 2,3,4,... the recurrence relation:

1 2

1( ) [( ) ( ) ( )]i i i i i i

i

f b c f d fa

ξ ξ ξ ξ− −= + −

Titus Beu 2011

Cheybyshev polynomials of 1st kind :

Converge much faster than any other series expansion on [-1,1]

Recurrence relations:

[ ]

0 1

1 2

2

1

( ) 1, ( )

( ) 2 ( ) ( ), 2,3, ,

( ) ( ) ( ) ( 1)

i i i

n n n

T x T x x

T x xT x T x i n

T x n xT x T x x

− −

′−

= =

= − =

= − −

12/7/2011

10

Titus Beu 2011

//===========================================================================

float Chebyshev(int n, float x, float *d)//---------------------------------------------------------------------------

Evaluates the Chebyshev polynomial of 1st kind and its first derivative (*d)//---------------------------------------------------------------------------

{float f, fm1, fm2, x2;

int i;

if (n == 0) {f = 1.0; *d = 0.0;

} else {f = x; fm1 = 1.0; x2 = 2*x;

for (i=2; i<=n; i++) {fm2 = fm1; fm1 = f;

f = x2*fm1 - fm2;}

*d = (x*x-1.0) ? n*(x*f-fm1)/(x*x-1.0) : n*n*f/x;}

return f;}

//===========================================================================

float Chebyshev(int n, float x, float *d)//---------------------------------------------------------------------------

Evaluates the Chebyshev polynomial of 1st kind and its first derivative (*d)//---------------------------------------------------------------------------

{float f, fm1, fm2, x2;

int i;

if (n == 0) {f = 1.0; *d = 0.0;

} else {f = x; fm1 = 1.0; x2 = 2*x;

for (i=2; i<=n; i++) {fm2 = fm1; fm1 = f;

f = x2*fm1 - fm2;}

*d = (x*x-1.0) ? n*(x*f-fm1)/(x*x-1.0) : n*n*f/x;}

return f;}

Titus Beu 2011

//===========================================================================

float Legendre(int n, float x, float *d)//---------------------------------------------------------------------------

Evaluates the Legendre polynomial and its first derivative (*d)//---------------------------------------------------------------------------

{float f, fm1, fm2;

int i;

if (n == 0) {f = 1.0; *d = 0.0;

} else {f = x; fm1 = 1.0;

for (i=2; i<=n; i++) {fm2 = fm1; fm1 = f;

f = ((2*i-1)*x*fm1 - (i-1)*fm2)/i;}

*d = (x*x-1.0) ? n*(x*f-fm1)/(x*x-1.0) : 0.5*n*(n+1)*f/x;}

return f;}

//===========================================================================

float Legendre(int n, float x, float *d)//---------------------------------------------------------------------------

Evaluates the Legendre polynomial and its first derivative (*d)//---------------------------------------------------------------------------

{float f, fm1, fm2;

int i;

if (n == 0) {f = 1.0; *d = 0.0;

} else {f = x; fm1 = 1.0;

for (i=2; i<=n; i++) {fm2 = fm1; fm1 = f;

f = ((2*i-1)*x*fm1 - (i-1)*fm2)/i;}

*d = (x*x-1.0) ? n*(x*f-fm1)/(x*x-1.0) : 0.5*n*(n+1)*f/x;}

return f;}

12/7/2011

11

Titus Beu 2011

//===========================================================================

float Laguerre(int n, float x, float *d)//---------------------------------------------------------------------------

Evaluates the Laguerre polynomial and its first derivative (*d)//---------------------------------------------------------------------------

{float f, fm1, fm2;

int i;

if (n == 0) {f = 1.0; *d = 0.0;

} else {f = 1.0 - x; fm1 = 1.0;

for (i=2; i<=n; i++) {fm2 = fm1; fm1 = f;

f = ((2*i-1-x)*fm1 - (i-1)*fm2)/i;}

*d = x ? n*(f-fm1)/x : -n*f;}

return f;}

//===========================================================================

float Laguerre(int n, float x, float *d)//---------------------------------------------------------------------------

Evaluates the Laguerre polynomial and its first derivative (*d)//---------------------------------------------------------------------------

{float f, fm1, fm2;

int i;

if (n == 0) {f = 1.0; *d = 0.0;

} else {f = 1.0 - x; fm1 = 1.0;

for (i=2; i<=n; i++) {fm2 = fm1; fm1 = f;

f = ((2*i-1-x)*fm1 - (i-1)*fm2)/i;}

*d = x ? n*(f-fm1)/x : -n*f;}

return f;}

Titus Beu 2011

//===========================================================================

float Hermite(int n, float x, float *d)//---------------------------------------------------------------------------

Evaluates the Hermite polynomial and its first derivative (*d)//---------------------------------------------------------------------------

{float f, fm1, fm2, x2;

int i;

if (n == 0) {f = 1.0; *d = 0.0;

} else {f = 2*x; fm1 = 1.0; x2 = 2*x;

for (i=2; i<=n; i++) {fm2 = fm1; fm1 = f;

f = x2*fm1 - 2*(i-1)*fm2;}

*d = 2*n*fm1;}

return f;}

//===========================================================================

float Hermite(int n, float x, float *d)//---------------------------------------------------------------------------

Evaluates the Hermite polynomial and its first derivative (*d)//---------------------------------------------------------------------------

{float f, fm1, fm2, x2;

int i;

if (n == 0) {f = 1.0; *d = 0.0;

} else {f = 2*x; fm1 = 1.0; x2 = 2*x;

for (i=2; i<=n; i++) {fm2 = fm1; fm1 = f;

f = x2*fm1 - 2*(i-1)*fm2;}

*d = 2*n*fm1;}

return f;}

12/7/2011

12

Titus Beu 2011

Separation of variables for certain differential equations in spherical coordinates –wave equation, Schrödinger's equation, Laplace's equation

Equation of spherical harmonics:

Spherical harmonics:

Orthonormation relation:

1sinθ

∂∂θ

sinθ ∂Ylm

∂θ+ 1

sin2θ∂2Ylm

∂ϕ2+ ll + 1Ylm = 0,

l = 0,1,2,… , − l ≤ m ≤ l

Ylm θ,ϕ = 2l + 14π

l − m!l + m!

P lm cosθeimϕ

Yl,−m θ,ϕ = −1m Ylm∗ θ,ϕ, m ≥ 0

∫0

2πdϕ ∫

0

πY

l ′m ′∗ θ,ϕYlm θ,ϕ sinθdθ = δ l′lδm ′m

Titus Beu 2011

{Ylm(θ,ϕ)} – complete othonormal basis set on the unity sphere L2(S1)

Any f ∈ L2(S1) can be uniquely expanded as a Fourier series:

fθ,ϕ = ∑l=0

∑m=−l

l

alm Ylm θ,ϕ

12/7/2011

13

Titus Beu 2011

Equation of associated Legendre functions:

Associated Legendre functions :

Orthonormation relation:

{Plm(x)} – complete othonormal basis set on L2([-1,1])

Any f ∈ L2([-1,1]) can be uniquely expanded as a Fourier series:

1 − x 2d2P l

m

dx 2− 2x

dP lm

dx+ ll + 1 − m2

1 − x 2P l

m = 0

P lm x = −1m 1 − x 2m /2 dm

dx m P lx.

∫−1

1

Pl′m xP l

m xdx = 22l + 1

l + m!l − m!

δ l′l.

fx = ∑l=0

∑m=−l

l

a lm P lm x.

Titus Beu 2011

Recurrence relation:

Starting values:

i − mP im x = 2i − 1xP i−1

m x − i + m − 1P i−2m x,

i = m + 1,… , l

Pm−1m = 0

Pmm x = −1m 2m − 1!!1 − x 2m /2

= ∏i=1

m

2i − 1 − 1 − x 2

12/7/2011

14

Titus Beu 2011

//===========================================================================

float FLegendre(int l, int m, float x)//---------------------------------------------------------------------------

Evaluates the associated Legendre function of orders l and m//---------------------------------------------------------------------------

{float p, pm1, pm2, sqx;

int i;

if (l < m) return 0.0;p = 1.0; pm1 = 0.0; /* P(m,m,x), P(m-1,m,x) */

if (m) {sqx = -sqrt(1.0-x*x);

for (i=1; i<=m; i++) p *= (2*i-1) * sqx;}

for (i=m+1; i<=l; i++) { /* recurenta */

pm2 = pm1; pm1 = p;p = ((2*i-1)*x*pm1 - (i+m-1)*pm2)/(i-m);

}return p;

}

//===========================================================================

float FLegendre(int l, int m, float x)//---------------------------------------------------------------------------

Evaluates the associated Legendre function of orders l and m//---------------------------------------------------------------------------

{float p, pm1, pm2, sqx;

int i;

if (l < m) return 0.0;p = 1.0; pm1 = 0.0; /* P(m,m,x), P(m-1,m,x) */

if (m) {sqx = -sqrt(1.0-x*x);

for (i=1; i<=m; i++) p *= (2*i-1) * sqx;}

for (i=m+1; i<=l; i++) { /* recurenta */

pm2 = pm1; pm1 = p;p = ((2*i-1)*x*pm1 - (i+m-1)*pm2)/(i-m);

}return p;

}

Titus Beu 2011

Solutions of the radial quantum equations of scattering

Differential equation:

Particular solutions:

Spherical Bessel functions (1st kind), jn(x) – regular

Spherical Neumann functions (2nd kind), yn(x) – non-regular

Particular orders:

Recurrence relation:

x 2 fn′′x + 2xfn

′ x + x 2 − nn + 1fnx = 0, n = 0,±1,±2,…

[ ] [ ]

0 0

1 0 1 0

sin cos( ) , ( ) ,

1 1( ) ( ) cos , ( ) ( ) sin

x xj x y x

x x

j x j x x y x y x xx x

= = −

= − = −

f ix = 2i − 1x f i−1x − f i−2x

12/7/2011

15

Titus Beu 2011

Spherical Bessel functions (1st kind) –regular solution

Spherical Neumannfunctions (2nd kind) –non-regular solution

Titus Beu 2011

Spherical Neumann functions – stable ascending recurrence

//===========================================================================

float SBessy(int n, float x)//---------------------------------------------------------------------------

Returns the spherical Neumann function y_n(x)//---------------------------------------------------------------------------

{float y, y0, y1;

int i;

y0 = -cos(x)/x; if (n == 0) return y0;y1 = (y0 - sin(x))/x; if (n == 1) return y1;

for (i=2; i<=n; i++) {

y = (2*i-1)/x*y1 - y0;y0 = y1; y1 = y;

}return y;

}

//===========================================================================

float SBessy(int n, float x)//---------------------------------------------------------------------------

Returns the spherical Neumann function y_n(x)//---------------------------------------------------------------------------

{float y, y0, y1;

int i;

y0 = -cos(x)/x; if (n == 0) return y0;y1 = (y0 - sin(x))/x; if (n == 1) return y1;

for (i=2; i<=n; i++) {

y = (2*i-1)/x*y1 - y0;y0 = y1; y1 = y;

}return y;

}

12/7/2011

16

Titus Beu 2011

Spherical Bessel functions – conditionally stable ascending recurrence

For n > |x|, the truncation errors accumulate for ascending recurrence

Miller’s algorithm – descending recurrence with arbitrary starting values

Ideea – homogeneous differential equation – solutions determined up to factor

jn(x) requested function – consider an order N > n and the descending recurrence:

New functions are proportional to the genuine ones:

Factor determined from n = 0:

2 1

1 2

0, 1,

2 3( ) ( ) ( ), , 1, ,0

N N

i i i

j j N n

ij x j x j x i N N

x

+ +

+ +

= = >

+= − = −

� �

� � � …

j̃n = kjn

jn = j0 /j̃0 j̃n

Titus Beu 2011

For n < |x| ascending recurrence is always stable

Under which conditions descending recurrence has to be employed?

Which is the order N from which descending recurrence has to be started?

For n > |x| only the first term in the recurrence relation is maintained:

Net increase factor of jN with respect to jn:

Criterion: if f > 108 – descending recurrence – ascending recurrence is unstable

1

2 1( ) ( ), , 1, ,i i

ij x j x i n n N

x−

−= +� …

2 1N

i n

if

x=

−= ∏

12/7/2011

17

Titus Beu 2011

//===========================================================================

float SBessj(int n, float x)//---------------------------------------------------------------------------

Returns the spherical Besseln function y_n(x)//---------------------------------------------------------------------------

{float j, j0, j1, j2, jn;

int i, nmax;

if (x == 0.0) return (n == 0 ? 1.0 : 0.0);j0 = sin(x)/x; if (n == 0) return j0;

j1 = (j0 - cos(x))/x; if (n == 1) return j1;

nmax = 0; // determine direction of stable recurrenceif ((float)n >= fabs(x)) {

jn = 1.;for (i=n; i<=(n+50); i++) {

jn *= (2*i-1)/x; // net increase factorif (jn >= 1e8) {nmax = i + 10; break;}

}}

if (nmax == 0) { // ascending recurrence

for (i=2; i<=n; i++) {j = (2*i-1)/x*j1 - j0;

j0 = j1; j1 = j;}

return j;} else { // descending recurrence

j2 = 0.; j1 = 1e-20;for (i=nmax; i>=0; i--) {

j = (2*i+3)/x*j1 - j2;j2 = j1; j1 = j;

if (i == n) jn = j; // unnormalized jn}

return (j0/j)*jn; // normalize jn}

}

//===========================================================================

float SBessj(int n, float x)//---------------------------------------------------------------------------

Returns the spherical Besseln function y_n(x)//---------------------------------------------------------------------------

{float j, j0, j1, j2, jn;

int i, nmax;

if (x == 0.0) return (n == 0 ? 1.0 : 0.0);j0 = sin(x)/x; if (n == 0) return j0;

j1 = (j0 - cos(x))/x; if (n == 1) return j1;

nmax = 0; // determine direction of stable recurrenceif ((float)n >= fabs(x)) {

jn = 1.;for (i=n; i<=(n+50); i++) {

jn *= (2*i-1)/x; // net increase factorif (jn >= 1e8) {nmax = i + 10; break;}

}}

if (nmax == 0) { // ascending recurrence

for (i=2; i<=n; i++) {j = (2*i-1)/x*j1 - j0;

j0 = j1; j1 = j;}

return j;} else { // descending recurrence

j2 = 0.; j1 = 1e-20;for (i=nmax; i>=0; i--) {

j = (2*i+3)/x*j1 - j2;j2 = j1; j1 = j;

if (i == n) jn = j; // unnormalized jn}

return (j0/j)*jn; // normalize jn}

}