123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884 |
- /* jv.c
- *
- * Bessel function of noninteger order
- *
- *
- *
- * SYNOPSIS:
- *
- * double v, x, y, jv();
- *
- * y = jv( v, x );
- *
- *
- *
- * DESCRIPTION:
- *
- * Returns Bessel function of order v of the argument,
- * where v is real. Negative x is allowed if v is an integer.
- *
- * Several expansions are included: the ascending power
- * series, the Hankel expansion, and two transitional
- * expansions for large v. If v is not too large, it
- * is reduced by recurrence to a region of best accuracy.
- * The transitional expansions give 12D accuracy for v > 500.
- *
- *
- *
- * ACCURACY:
- * Results for integer v are indicated by *, where x and v
- * both vary from -125 to +125. Otherwise,
- * x ranges from 0 to 125, v ranges as indicated by "domain."
- * Error criterion is absolute, except relative when |jv()| > 1.
- *
- * arithmetic v domain x domain # trials peak rms
- * IEEE 0,125 0,125 100000 4.6e-15 2.2e-16
- * IEEE -125,0 0,125 40000 5.4e-11 3.7e-13
- * IEEE 0,500 0,500 20000 4.4e-15 4.0e-16
- * Integer v:
- * IEEE -125,125 -125,125 50000 3.5e-15* 1.9e-16*
- *
- */
- /*
- Cephes Math Library Release 2.8: June, 2000
- Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
- */
- #include <math.h>
- #define DEBUG 0
- #ifdef DEC
- #define MAXGAM 34.84425627277176174
- #else
- #define MAXGAM 171.624376956302725
- #endif
- #ifdef ANSIPROT
- extern int airy ( double, double *, double *, double *, double * );
- extern double fabs ( double );
- extern double floor ( double );
- extern double frexp ( double, int * );
- extern double polevl ( double, void *, int );
- extern double j0 ( double );
- extern double j1 ( double );
- extern double sqrt ( double );
- extern double cbrt ( double );
- extern double exp ( double );
- extern double log ( double );
- extern double sin ( double );
- extern double cos ( double );
- extern double acos ( double );
- extern double pow ( double, double );
- extern double gamma ( double );
- extern double lgam ( double );
- static double recur(double *, double, double *, int);
- static double jvs(double, double);
- static double hankel(double, double);
- static double jnx(double, double);
- static double jnt(double, double);
- #else
- int airy();
- double fabs(), floor(), frexp(), polevl(), j0(), j1(), sqrt(), cbrt();
- double exp(), log(), sin(), cos(), acos(), pow(), gamma(), lgam();
- static double recur(), jvs(), hankel(), jnx(), jnt();
- #endif
- extern double MAXNUM, MACHEP, MINLOG, MAXLOG;
- #define BIG 1.44115188075855872E+17
- double jv( n, x )
- double n, x;
- {
- double k, q, t, y, an;
- int i, sign, nint;
- nint = 0; /* Flag for integer n */
- sign = 1; /* Flag for sign inversion */
- an = fabs( n );
- y = floor( an );
- if( y == an )
- {
- nint = 1;
- i = an - 16384.0 * floor( an/16384.0 );
- if( n < 0.0 )
- {
- if( i & 1 )
- sign = -sign;
- n = an;
- }
- if( x < 0.0 )
- {
- if( i & 1 )
- sign = -sign;
- x = -x;
- }
- if( n == 0.0 )
- return( j0(x) );
- if( n == 1.0 )
- return( sign * j1(x) );
- }
- if( (x < 0.0) && (y != an) )
- {
- mtherr( "Jv", DOMAIN );
- y = 0.0;
- goto done;
- }
- y = fabs(x);
- if( y < MACHEP )
- goto underf;
- k = 3.6 * sqrt(y);
- t = 3.6 * sqrt(an);
- if( (y < t) && (an > 21.0) )
- return( sign * jvs(n,x) );
- if( (an < k) && (y > 21.0) )
- return( sign * hankel(n,x) );
- if( an < 500.0 )
- {
- /* Note: if x is too large, the continued
- * fraction will fail; but then the
- * Hankel expansion can be used.
- */
- if( nint != 0 )
- {
- k = 0.0;
- q = recur( &n, x, &k, 1 );
- if( k == 0.0 )
- {
- y = j0(x)/q;
- goto done;
- }
- if( k == 1.0 )
- {
- y = j1(x)/q;
- goto done;
- }
- }
- if( an > 2.0 * y )
- goto rlarger;
- if( (n >= 0.0) && (n < 20.0)
- && (y > 6.0) && (y < 20.0) )
- {
- /* Recur backwards from a larger value of n
- */
- rlarger:
- k = n;
- y = y + an + 1.0;
- if( y < 30.0 )
- y = 30.0;
- y = n + floor(y-n);
- q = recur( &y, x, &k, 0 );
- y = jvs(y,x) * q;
- goto done;
- }
- if( k <= 30.0 )
- {
- k = 2.0;
- }
- else if( k < 90.0 )
- {
- k = (3*k)/4;
- }
- if( an > (k + 3.0) )
- {
- if( n < 0.0 )
- k = -k;
- q = n - floor(n);
- k = floor(k) + q;
- if( n > 0.0 )
- q = recur( &n, x, &k, 1 );
- else
- {
- t = k;
- k = n;
- q = recur( &t, x, &k, 1 );
- k = t;
- }
- if( q == 0.0 )
- {
- underf:
- y = 0.0;
- goto done;
- }
- }
- else
- {
- k = n;
- q = 1.0;
- }
- /* boundary between convergence of
- * power series and Hankel expansion
- */
- y = fabs(k);
- if( y < 26.0 )
- t = (0.0083*y + 0.09)*y + 12.9;
- else
- t = 0.9 * y;
- if( x > t )
- y = hankel(k,x);
- else
- y = jvs(k,x);
- #if DEBUG
- printf( "y = %.16e, recur q = %.16e\n", y, q );
- #endif
- if( n > 0.0 )
- y /= q;
- else
- y *= q;
- }
- else
- {
- /* For large n, use the uniform expansion
- * or the transitional expansion.
- * But if x is of the order of n**2,
- * these may blow up, whereas the
- * Hankel expansion will then work.
- */
- if( n < 0.0 )
- {
- mtherr( "Jv", TLOSS );
- y = 0.0;
- goto done;
- }
- t = x/n;
- t /= n;
- if( t > 0.3 )
- y = hankel(n,x);
- else
- y = jnx(n,x);
- }
- done: return( sign * y);
- }
- /* Reduce the order by backward recurrence.
- * AMS55 #9.1.27 and 9.1.73.
- */
- static double recur( n, x, newn, cancel )
- double *n;
- double x;
- double *newn;
- int cancel;
- {
- double pkm2, pkm1, pk, qkm2, qkm1;
- /* double pkp1; */
- double k, ans, qk, xk, yk, r, t, kf;
- static double big = BIG;
- int nflag, ctr;
- /* continued fraction for Jn(x)/Jn-1(x) */
- if( *n < 0.0 )
- nflag = 1;
- else
- nflag = 0;
- fstart:
- #if DEBUG
- printf( "recur: n = %.6e, newn = %.6e, cfrac = ", *n, *newn );
- #endif
- pkm2 = 0.0;
- qkm2 = 1.0;
- pkm1 = x;
- qkm1 = *n + *n;
- xk = -x * x;
- yk = qkm1;
- ans = 1.0;
- ctr = 0;
- do
- {
- yk += 2.0;
- pk = pkm1 * yk + pkm2 * xk;
- qk = qkm1 * yk + qkm2 * xk;
- pkm2 = pkm1;
- pkm1 = pk;
- qkm2 = qkm1;
- qkm1 = qk;
- if( qk != 0 )
- r = pk/qk;
- else
- r = 0.0;
- if( r != 0 )
- {
- t = fabs( (ans - r)/r );
- ans = r;
- }
- else
- t = 1.0;
- if( ++ctr > 1000 )
- {
- mtherr( "jv", UNDERFLOW );
- goto done;
- }
- if( t < MACHEP )
- goto done;
- if( fabs(pk) > big )
- {
- pkm2 /= big;
- pkm1 /= big;
- qkm2 /= big;
- qkm1 /= big;
- }
- }
- while( t > MACHEP );
- done:
- #if DEBUG
- printf( "%.6e\n", ans );
- #endif
- /* Change n to n-1 if n < 0 and the continued fraction is small
- */
- if( nflag > 0 )
- {
- if( fabs(ans) < 0.125 )
- {
- nflag = -1;
- *n = *n - 1.0;
- goto fstart;
- }
- }
- kf = *newn;
- /* backward recurrence
- * 2k
- * J (x) = --- J (x) - J (x)
- * k-1 x k k+1
- */
- pk = 1.0;
- pkm1 = 1.0/ans;
- k = *n - 1.0;
- r = 2 * k;
- do
- {
- pkm2 = (pkm1 * r - pk * x) / x;
- /* pkp1 = pk; */
- pk = pkm1;
- pkm1 = pkm2;
- r -= 2.0;
- /*
- t = fabs(pkp1) + fabs(pk);
- if( (k > (kf + 2.5)) && (fabs(pkm1) < 0.25*t) )
- {
- k -= 1.0;
- t = x*x;
- pkm2 = ( (r*(r+2.0)-t)*pk - r*x*pkp1 )/t;
- pkp1 = pk;
- pk = pkm1;
- pkm1 = pkm2;
- r -= 2.0;
- }
- */
- k -= 1.0;
- }
- while( k > (kf + 0.5) );
- /* Take the larger of the last two iterates
- * on the theory that it may have less cancellation error.
- */
- if( cancel )
- {
- if( (kf >= 0.0) && (fabs(pk) > fabs(pkm1)) )
- {
- k += 1.0;
- pkm2 = pk;
- }
- }
- *newn = k;
- #if DEBUG
- printf( "newn %.6e rans %.6e\n", k, pkm2 );
- #endif
- return( pkm2 );
- }
- /* Ascending power series for Jv(x).
- * AMS55 #9.1.10.
- */
- extern double PI;
- extern int sgngam;
- static double jvs( n, x )
- double n, x;
- {
- double t, u, y, z, k;
- int ex;
- z = -x * x / 4.0;
- u = 1.0;
- y = u;
- k = 1.0;
- t = 1.0;
- while( t > MACHEP )
- {
- u *= z / (k * (n+k));
- y += u;
- k += 1.0;
- if( y != 0 )
- t = fabs( u/y );
- }
- #if DEBUG
- printf( "power series=%.5e ", y );
- #endif
- t = frexp( 0.5*x, &ex );
- ex = ex * n;
- if( (ex > -1023)
- && (ex < 1023)
- && (n > 0.0)
- && (n < (MAXGAM-1.0)) )
- {
- t = pow( 0.5*x, n ) / gamma( n + 1.0 );
- #if DEBUG
- printf( "pow(.5*x, %.4e)/gamma(n+1)=%.5e\n", n, t );
- #endif
- y *= t;
- }
- else
- {
- #if DEBUG
- z = n * log(0.5*x);
- k = lgam( n+1.0 );
- t = z - k;
- printf( "log pow=%.5e, lgam(%.4e)=%.5e\n", z, n+1.0, k );
- #else
- t = n * log(0.5*x) - lgam(n + 1.0);
- #endif
- if( y < 0 )
- {
- sgngam = -sgngam;
- y = -y;
- }
- t += log(y);
- #if DEBUG
- printf( "log y=%.5e\n", log(y) );
- #endif
- if( t < -MAXLOG )
- {
- return( 0.0 );
- }
- if( t > MAXLOG )
- {
- mtherr( "Jv", OVERFLOW );
- return( MAXNUM );
- }
- y = sgngam * exp( t );
- }
- return(y);
- }
- /* Hankel's asymptotic expansion
- * for large x.
- * AMS55 #9.2.5.
- */
- static double hankel( n, x )
- double n, x;
- {
- double t, u, z, k, sign, conv;
- double p, q, j, m, pp, qq;
- int flag;
- m = 4.0*n*n;
- j = 1.0;
- z = 8.0 * x;
- k = 1.0;
- p = 1.0;
- u = (m - 1.0)/z;
- q = u;
- sign = 1.0;
- conv = 1.0;
- flag = 0;
- t = 1.0;
- pp = 1.0e38;
- qq = 1.0e38;
- while( t > MACHEP )
- {
- k += 2.0;
- j += 1.0;
- sign = -sign;
- u *= (m - k * k)/(j * z);
- p += sign * u;
- k += 2.0;
- j += 1.0;
- u *= (m - k * k)/(j * z);
- q += sign * u;
- t = fabs(u/p);
- if( t < conv )
- {
- conv = t;
- qq = q;
- pp = p;
- flag = 1;
- }
- /* stop if the terms start getting larger */
- if( (flag != 0) && (t > conv) )
- {
- #if DEBUG
- printf( "Hankel: convergence to %.4E\n", conv );
- #endif
- goto hank1;
- }
- }
- hank1:
- u = x - (0.5*n + 0.25) * PI;
- t = sqrt( 2.0/(PI*x) ) * ( pp * cos(u) - qq * sin(u) );
- #if DEBUG
- printf( "hank: %.6e\n", t );
- #endif
- return( t );
- }
- /* Asymptotic expansion for large n.
- * AMS55 #9.3.35.
- */
- static double lambda[] = {
- 1.0,
- 1.041666666666666666666667E-1,
- 8.355034722222222222222222E-2,
- 1.282265745563271604938272E-1,
- 2.918490264641404642489712E-1,
- 8.816272674437576524187671E-1,
- 3.321408281862767544702647E+0,
- 1.499576298686255465867237E+1,
- 7.892301301158651813848139E+1,
- 4.744515388682643231611949E+2,
- 3.207490090890661934704328E+3
- };
- static double mu[] = {
- 1.0,
- -1.458333333333333333333333E-1,
- -9.874131944444444444444444E-2,
- -1.433120539158950617283951E-1,
- -3.172272026784135480967078E-1,
- -9.424291479571202491373028E-1,
- -3.511203040826354261542798E+0,
- -1.572726362036804512982712E+1,
- -8.228143909718594444224656E+1,
- -4.923553705236705240352022E+2,
- -3.316218568547972508762102E+3
- };
- static double P1[] = {
- -2.083333333333333333333333E-1,
- 1.250000000000000000000000E-1
- };
- static double P2[] = {
- 3.342013888888888888888889E-1,
- -4.010416666666666666666667E-1,
- 7.031250000000000000000000E-2
- };
- static double P3[] = {
- -1.025812596450617283950617E+0,
- 1.846462673611111111111111E+0,
- -8.912109375000000000000000E-1,
- 7.324218750000000000000000E-2
- };
- static double P4[] = {
- 4.669584423426247427983539E+0,
- -1.120700261622299382716049E+1,
- 8.789123535156250000000000E+0,
- -2.364086914062500000000000E+0,
- 1.121520996093750000000000E-1
- };
- static double P5[] = {
- -2.8212072558200244877E1,
- 8.4636217674600734632E1,
- -9.1818241543240017361E1,
- 4.2534998745388454861E1,
- -7.3687943594796316964E0,
- 2.27108001708984375E-1
- };
- static double P6[] = {
- 2.1257013003921712286E2,
- -7.6525246814118164230E2,
- 1.0599904525279998779E3,
- -6.9957962737613254123E2,
- 2.1819051174421159048E2,
- -2.6491430486951555525E1,
- 5.7250142097473144531E-1
- };
- static double P7[] = {
- -1.9194576623184069963E3,
- 8.0617221817373093845E3,
- -1.3586550006434137439E4,
- 1.1655393336864533248E4,
- -5.3056469786134031084E3,
- 1.2009029132163524628E3,
- -1.0809091978839465550E2,
- 1.7277275025844573975E0
- };
- static double jnx( n, x )
- double n, x;
- {
- double zeta, sqz, zz, zp, np;
- double cbn, n23, t, z, sz;
- double pp, qq, z32i, zzi;
- double ak, bk, akl, bkl;
- int sign, doa, dob, nflg, k, s, tk, tkp1, m;
- static double u[8];
- static double ai, aip, bi, bip;
- /* Test for x very close to n.
- * Use expansion for transition region if so.
- */
- cbn = cbrt(n);
- z = (x - n)/cbn;
- if( fabs(z) <= 0.7 )
- return( jnt(n,x) );
- z = x/n;
- zz = 1.0 - z*z;
- if( zz == 0.0 )
- return(0.0);
- if( zz > 0.0 )
- {
- sz = sqrt( zz );
- t = 1.5 * (log( (1.0+sz)/z ) - sz ); /* zeta ** 3/2 */
- zeta = cbrt( t * t );
- nflg = 1;
- }
- else
- {
- sz = sqrt(-zz);
- t = 1.5 * (sz - acos(1.0/z));
- zeta = -cbrt( t * t );
- nflg = -1;
- }
- z32i = fabs(1.0/t);
- sqz = cbrt(t);
- /* Airy function */
- n23 = cbrt( n * n );
- t = n23 * zeta;
- #if DEBUG
- printf("zeta %.5E, Airy(%.5E)\n", zeta, t );
- #endif
- airy( t, &ai, &aip, &bi, &bip );
- /* polynomials in expansion */
- u[0] = 1.0;
- zzi = 1.0/zz;
- u[1] = polevl( zzi, P1, 1 )/sz;
- u[2] = polevl( zzi, P2, 2 )/zz;
- u[3] = polevl( zzi, P3, 3 )/(sz*zz);
- pp = zz*zz;
- u[4] = polevl( zzi, P4, 4 )/pp;
- u[5] = polevl( zzi, P5, 5 )/(pp*sz);
- pp *= zz;
- u[6] = polevl( zzi, P6, 6 )/pp;
- u[7] = polevl( zzi, P7, 7 )/(pp*sz);
- #if DEBUG
- for( k=0; k<=7; k++ )
- printf( "u[%d] = %.5E\n", k, u[k] );
- #endif
- pp = 0.0;
- qq = 0.0;
- np = 1.0;
- /* flags to stop when terms get larger */
- doa = 1;
- dob = 1;
- akl = MAXNUM;
- bkl = MAXNUM;
- for( k=0; k<=3; k++ )
- {
- tk = 2 * k;
- tkp1 = tk + 1;
- zp = 1.0;
- ak = 0.0;
- bk = 0.0;
- for( s=0; s<=tk; s++ )
- {
- if( doa )
- {
- if( (s & 3) > 1 )
- sign = nflg;
- else
- sign = 1;
- ak += sign * mu[s] * zp * u[tk-s];
- }
- if( dob )
- {
- m = tkp1 - s;
- if( ((m+1) & 3) > 1 )
- sign = nflg;
- else
- sign = 1;
- bk += sign * lambda[s] * zp * u[m];
- }
- zp *= z32i;
- }
- if( doa )
- {
- ak *= np;
- t = fabs(ak);
- if( t < akl )
- {
- akl = t;
- pp += ak;
- }
- else
- doa = 0;
- }
- if( dob )
- {
- bk += lambda[tkp1] * zp * u[0];
- bk *= -np/sqz;
- t = fabs(bk);
- if( t < bkl )
- {
- bkl = t;
- qq += bk;
- }
- else
- dob = 0;
- }
- #if DEBUG
- printf("a[%d] %.5E, b[%d] %.5E\n", k, ak, k, bk );
- #endif
- if( np < MACHEP )
- break;
- np /= n*n;
- }
- /* normalizing factor ( 4*zeta/(1 - z**2) )**1/4 */
- t = 4.0 * zeta/zz;
- t = sqrt( sqrt(t) );
- t *= ai*pp/cbrt(n) + aip*qq/(n23*n);
- return(t);
- }
- /* Asymptotic expansion for transition region,
- * n large and x close to n.
- * AMS55 #9.3.23.
- */
- static double PF2[] = {
- -9.0000000000000000000e-2,
- 8.5714285714285714286e-2
- };
- static double PF3[] = {
- 1.3671428571428571429e-1,
- -5.4920634920634920635e-2,
- -4.4444444444444444444e-3
- };
- static double PF4[] = {
- 1.3500000000000000000e-3,
- -1.6036054421768707483e-1,
- 4.2590187590187590188e-2,
- 2.7330447330447330447e-3
- };
- static double PG1[] = {
- -2.4285714285714285714e-1,
- 1.4285714285714285714e-2
- };
- static double PG2[] = {
- -9.0000000000000000000e-3,
- 1.9396825396825396825e-1,
- -1.1746031746031746032e-2
- };
- static double PG3[] = {
- 1.9607142857142857143e-2,
- -1.5983694083694083694e-1,
- 6.3838383838383838384e-3
- };
- static double jnt( n, x )
- double n, x;
- {
- double z, zz, z3;
- double cbn, n23, cbtwo;
- double ai, aip, bi, bip; /* Airy functions */
- double nk, fk, gk, pp, qq;
- double F[5], G[4];
- int k;
- cbn = cbrt(n);
- z = (x - n)/cbn;
- cbtwo = cbrt( 2.0 );
- /* Airy function */
- zz = -cbtwo * z;
- airy( zz, &ai, &aip, &bi, &bip );
- /* polynomials in expansion */
- zz = z * z;
- z3 = zz * z;
- F[0] = 1.0;
- F[1] = -z/5.0;
- F[2] = polevl( z3, PF2, 1 ) * zz;
- F[3] = polevl( z3, PF3, 2 );
- F[4] = polevl( z3, PF4, 3 ) * z;
- G[0] = 0.3 * zz;
- G[1] = polevl( z3, PG1, 1 );
- G[2] = polevl( z3, PG2, 2 ) * z;
- G[3] = polevl( z3, PG3, 2 ) * zz;
- #if DEBUG
- for( k=0; k<=4; k++ )
- printf( "F[%d] = %.5E\n", k, F[k] );
- for( k=0; k<=3; k++ )
- printf( "G[%d] = %.5E\n", k, G[k] );
- #endif
- pp = 0.0;
- qq = 0.0;
- nk = 1.0;
- n23 = cbrt( n * n );
- for( k=0; k<=4; k++ )
- {
- fk = F[k]*nk;
- pp += fk;
- if( k != 4 )
- {
- gk = G[k]*nk;
- qq += gk;
- }
- #if DEBUG
- printf("fk[%d] %.5E, gk[%d] %.5E\n", k, fk, k, gk );
- #endif
- nk /= n23;
- }
- fk = cbtwo * ai * pp/cbn + cbrt(4.0) * aip * qq/n;
- return(fk);
- }
|