| 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, 2000Copyright 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 ANSIPROTextern 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);#elseint 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();#endifextern double MAXNUM, MACHEP, MINLOG, MAXLOG;#define BIG  1.44115188075855872E+17double 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 DEBUGprintf( "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 DEBUGprintf( "recur: n = %.6e, newn = %.6e, cfrac = ", *n, *newn );#endifpkm2 = 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 DEBUGprintf( "%.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 DEBUGprintf( "newn %.6e rans %.6e\n", k, pkm2 );#endifreturn( 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 DEBUGprintf( "power series=%.5e ", y );#endift = 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 DEBUGprintf( "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 DEBUGprintf( "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 DEBUGprintf( "hank: %.6e\n", t );#endifreturn( 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 DEBUGprintf("zeta %.5E, Airy(%.5E)\n", zeta, t );#endifairy( 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 DEBUGfor( k=0; k<=7; k++ )	printf( "u[%d] = %.5E\n", k, u[k] );#endifpp = 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 DEBUGfor( 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] );#endifpp = 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);}
 |