/* 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 12 D 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 . 6 e - 15 2 . 2 e - 16
* IEEE - 125 , 0 0 , 125 40000 5 . 4 e - 11 3 . 7 e - 13
* IEEE 0 , 500 0 , 500 20000 4 . 4 e - 15 4 . 0 e - 16
* Integer v :
* IEEE - 125 , 125 - 125 , 125 50000 3 . 5 e - 15 * 1 . 9 e - 16 *
*
*/
/*
Cephes Math Library Release 2 . 8 : June , 2000
Copyright 1984 , 1987 , 1989 , 1992 , 2000 by Stephen L . Moshier
*/
#include "mconf.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 .44115188075855872 E+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
* 2 k
* 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 .0 e38;
qq = 1 .0 e38;
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 .041666666666666666666667 E-1 ,
8 .355034722222222222222222 E-2 ,
1 .282265745563271604938272 E-1 ,
2 .918490264641404642489712 E-1 ,
8 .816272674437576524187671 E-1 ,
3 .321408281862767544702647 E+0 ,
1 .499576298686255465867237 E+1 ,
7 .892301301158651813848139 E+1 ,
4 .744515388682643231611949 E+2 ,
3 .207490090890661934704328 E+3 };
static double mu[] = {1 .0 ,
-1 .458333333333333333333333 E-1 ,
-9 .874131944444444444444444 E-2 ,
-1 .433120539158950617283951 E-1 ,
-3 .172272026784135480967078 E-1 ,
-9 .424291479571202491373028 E-1 ,
-3 .511203040826354261542798 E+0 ,
-1 .572726362036804512982712 E+1 ,
-8 .228143909718594444224656 E+1 ,
-4 .923553705236705240352022 E+2 ,
-3 .316218568547972508762102 E+3 };
static double P1[] = {-2 .083333333333333333333333 E-1 ,
1 .250000000000000000000000 E-1 };
static double P2[] = {3 .342013888888888888888889 E-1 ,
-4 .010416666666666666666667 E-1 ,
7 .031250000000000000000000 E-2 };
static double P3[] = {
-1 .025812596450617283950617 E+0 , 1 .846462673611111111111111 E+0 ,
-8 .912109375000000000000000 E-1 , 7 .324218750000000000000000 E-2 };
static double P4[] = {
4 .669584423426247427983539 E+0 , -1 .120700261622299382716049 E+1 ,
8 .789123535156250000000000 E+0 , -2 .364086914062500000000000 E+0 ,
1 .121520996093750000000000 E-1 };
static double P5[] = {-2 .8212072558200244877 E1, 8 .4636217674600734632 E1,
-9 .1818241543240017361 E1, 4 .2534998745388454861 E1,
-7 .3687943594796316964 E0, 2 .27108001708984375 E-1 };
static double P6[] = {2 .1257013003921712286 E2, -7 .6525246814118164230 E2,
1 .0599904525279998779 E3, -6 .9957962737613254123 E2,
2 .1819051174421159048 E2, -2 .6491430486951555525 E1,
5 .7250142097473144531 E-1 };
static double P7[] = {-1 .9194576623184069963 E3, 8 .0617221817373093845 E3,
-1 .3586550006434137439 E4, 1 .1655393336864533248 E4,
-5 .3056469786134031084 E3, 1 .2009029132163524628 E3,
-1 .0809091978839465550 E2, 1 .7277275025844573975 E0};
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 .0000000000000000000 e-2 , 8 .5714285714285714286 e-2 };
static double PF3[] = {1 .3671428571428571429 e-1 , -5 .4920634920634920635 e-2 ,
-4 .4444444444444444444 e-3 };
static double PF4[] = {1 .3500000000000000000 e-3 , -1 .6036054421768707483 e-1 ,
4 .2590187590187590188 e-2 , 2 .7330447330447330447 e-3 };
static double PG1[] = {-2 .4285714285714285714 e-1 , 1 .4285714285714285714 e-2 };
static double PG2[] = {-9 .0000000000000000000 e-3 , 1 .9396825396825396825 e-1 ,
-1 .1746031746031746032 e-2 };
static double PG3[] = {1 .9607142857142857143 e-2 , -1 .5983694083694083694 e-1 ,
6 .3838383838383838384 e-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);
}
Messung V0.5 in Prozent C=96 H=93 G=94
¤ Dauer der Verarbeitung: 0.8 Sekunden
¤
*© Formatika GbR, Deutschland