/* struve.c
*
* Struve function
*
*
*
* SYNOPSIS:
*
* double v, x, y, struve();
*
* y = struve( v, x );
*
*
*
* DESCRIPTION:
*
* Computes the Struve function Hv(x) of order v, argument x.
* Negative x is rejected unless v is an integer.
*
* This module also contains the hypergeometric functions 1F2
* and 3F0 and a routine for the Bessel function Yv(x) with
* noninteger v.
*
*
*
* ACCURACY:
*
* Not accurately characterized, but spot checked against tables.
*
*/
/*
Cephes Math Library Release 2.81: June, 2000
Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier
*/
#include "mconf.h"
#define DEBUG 0
#ifdef ANSIPROT
extern double md_gamma ( double );
extern double md_pow ( double, double );
extern double sqrt ( double );
extern double md_yn ( int, double );
extern double jv ( double, double );
extern double md_fabs ( double );
extern double md_floor ( double );
extern double md_sin ( double );
extern double md_cos ( double );
double yv ( double, double );
double onef2 (double, double, double, double, double * );
double threef0 (double, double, double, double, double * );
#else
double md_gamma(), md_pow(), sqrt(), md_yn(), yv(), jv(), md_fabs(), md_floor();
double md_sin(), md_cos();
double onef2(), threef0();
#endif
static double stop = 1.37e-17;
extern double MACHEP;
double onef2( a, b, c, x, err )
double a, b, c, x;
double *err;
{
double n, a0, sum, t;
double an, bn, cn, max, z;
an = a;
bn = b;
cn = c;
a0 = 1.0;
sum = 1.0;
n = 1.0;
t = 1.0;
max = 0.0;
do
{
if( an == 0 )
goto done;
if( bn == 0 )
goto error;
if( cn == 0 )
goto error;
if( (a0 > 1.0e34) || (n > 200) )
goto error;
a0 *= (an * x) / (bn * cn * n);
sum += a0;
an += 1.0;
bn += 1.0;
cn += 1.0;
n += 1.0;
z = md_fabs( a0 );
if( z > max )
max = z;
if( sum != 0 )
t = md_fabs( a0 / sum );
else
t = z;
}
while( t > stop );
done:
*err = md_fabs( MACHEP*max /sum );
#if DEBUG
printf(" onef2 cancellation error %.5E\n", *err );
#endif
goto xit;
error:
#if DEBUG
printf("onef2 does not converge\n");
#endif
*err = 1.0e38;
xit:
#if DEBUG
printf("onef2( %.2E %.2E %.2E %.5E ) = %.3E %.6E\n", a, b, c, x, n, sum);
#endif
return(sum);
}
double threef0( a, b, c, x, err )
double a, b, c, x;
double *err;
{
double n, a0, sum, t, conv, conv1;
double an, bn, cn, max, z;
an = a;
bn = b;
cn = c;
a0 = 1.0;
sum = 1.0;
n = 1.0;
t = 1.0;
max = 0.0;
conv = 1.0e38;
conv1 = conv;
do
{
if( an == 0.0 )
goto done;
if( bn == 0.0 )
goto done;
if( cn == 0.0 )
goto done;
if( (a0 > 1.0e34) || (n > 200) )
goto error;
a0 *= (an * bn * cn * x) / n;
an += 1.0;
bn += 1.0;
cn += 1.0;
n += 1.0;
z = md_fabs( a0 );
if( z > max )
max = z;
if( z >= conv )
{
if( (z < max) && (z > conv1) )
goto done;
}
conv1 = conv;
conv = z;
sum += a0;
if( sum != 0 )
t = md_fabs( a0 / sum );
else
t = z;
}
while( t > stop );
done:
t = md_fabs( MACHEP*max/sum );
#if DEBUG
printf(" threef0 cancellation error %.5E\n", t );
#endif
max = md_fabs( conv/sum );
if( max > t )
t = max;
#if DEBUG
printf(" threef0 convergence %.5E\n", max );
#endif
goto xit;
error:
#if DEBUG
printf("threef0 does not converge\n");
#endif
t = 1.0e38;
xit:
#if DEBUG
printf("threef0( %.2E %.2E %.2E %.5E ) = %.3E %.6E\n", a, b, c, x, n, sum);
#endif
*err = t;
return(sum);
}
extern double PI;
double struve( v, x )
double v, x;
{
double y, ya, f, g, h, t;
double onef2err, threef0err;
f = md_floor(v);
if( (v < 0) && ( v-f == 0.5 ) )
{
y = jv( -v, x );
f = 1.0 - f;
g = 2.0 * md_floor(f/2.0);
if( g != f )
y = -y;
return(y);
}
t = 0.25*x*x;
f = md_fabs(x);
g = 1.5 * md_fabs(v);
if( (f > 30.0) && (f > g) )
{
onef2err = 1.0e38;
y = 0.0;
}
else
{
y = onef2( 1.0, 1.5, 1.5+v, -t, &onef2err );
}
if( (f < 18.0) || (x < 0.0) )
{
threef0err = 1.0e38;
ya = 0.0;
}
else
{
ya = threef0( 1.0, 0.5, 0.5-v, -1.0/t, &threef0err );
}
f = sqrt( PI );
h = md_pow( 0.5*x, v-1.0 );
if( onef2err <= threef0err )
{
g = md_gamma( v + 1.5 );
y = y * h * t / ( 0.5 * f * g );
return(y);
}
else
{
g = md_gamma( v + 0.5 );
ya = ya * h / ( f * g );
ya = ya + yv( v, x );
return(ya);
}
}
/* Bessel function of noninteger order
*/
double yv( v, x )
double v, x;
{
double y, t;
int n;
y = md_floor( v );
if( y == v )
{
n = v;
y = md_yn( n, x );
return( y );
}
t = PI * v;
y = (md_cos(t) * jv( v, x ) - jv( -v, x ))/md_sin(t);
return( y );
}
/* Crossover points between ascending series and asymptotic series
* for Struve function
*
* v x
*
* 0 19.2
* 1 18.95
* 2 19.15
* 3 19.3
* 5 19.7
* 10 21.35
* 20 26.35
* 30 32.31
* 40 40.0
*/