|
Packit |
67cb25 |
/* specfunc/bessel.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003 Gerard Jungman
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
67cb25 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
67cb25 |
* the Free Software Foundation; either version 3 of the License, or (at
|
|
Packit |
67cb25 |
* your option) any later version.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
67cb25 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
67cb25 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
67cb25 |
* General Public License for more details.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
67cb25 |
* along with this program; if not, write to the Free Software
|
|
Packit |
67cb25 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Author: G. Jungman */
|
|
Packit |
67cb25 |
/* Miscellaneous support functions for Bessel function evaluations.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
#include <config.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_math.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_errno.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_sf_airy.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_sf_elementary.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_sf_exp.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_sf_gamma.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_sf_trig.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include "error.h"
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include "bessel_amp_phase.h"
|
|
Packit |
67cb25 |
#include "bessel_temme.h"
|
|
Packit |
67cb25 |
#include "bessel.h"
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#define CubeRoot2_ 1.25992104989487316476721060728
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Debye functions [Abramowitz+Stegun, 9.3.9-10] */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
inline static double
|
|
Packit |
67cb25 |
debye_u1(const double * tpow)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return (3.0*tpow[1] - 5.0*tpow[3])/24.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
inline static double
|
|
Packit |
67cb25 |
debye_u2(const double * tpow)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return (81.0*tpow[2] - 462.0*tpow[4] + 385.0*tpow[6])/1152.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
inline
|
|
Packit |
67cb25 |
static double debye_u3(const double * tpow)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return (30375.0*tpow[3] - 369603.0*tpow[5] + 765765.0*tpow[7] - 425425.0*tpow[9])/414720.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
inline
|
|
Packit |
67cb25 |
static double debye_u4(const double * tpow)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return (4465125.0*tpow[4] - 94121676.0*tpow[6] + 349922430.0*tpow[8] -
|
|
Packit |
67cb25 |
446185740.0*tpow[10] + 185910725.0*tpow[12])/39813120.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
inline
|
|
Packit |
67cb25 |
static double debye_u5(const double * tpow)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return (1519035525.0*tpow[5] - 49286948607.0*tpow[7] +
|
|
Packit |
67cb25 |
284499769554.0*tpow[9] - 614135872350.0*tpow[11] +
|
|
Packit |
67cb25 |
566098157625.0*tpow[13] - 188699385875.0*tpow[15])/6688604160.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#if 0
|
|
Packit |
67cb25 |
inline
|
|
Packit |
67cb25 |
static double debye_u6(const double * tpow)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
return (2757049477875.0*tpow[6] - 127577298354750.0*tpow[8] +
|
|
Packit |
67cb25 |
1050760774457901.0*tpow[10] - 3369032068261860.0*tpow[12] +
|
|
Packit |
67cb25 |
5104696716244125.0*tpow[14] - 3685299006138750.0*tpow[16] +
|
|
Packit |
67cb25 |
1023694168371875.0*tpow[18])/4815794995200.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_bessel_IJ_taylor_e(const double nu, const double x,
|
|
Packit |
67cb25 |
const int sign,
|
|
Packit |
67cb25 |
const int kmax,
|
|
Packit |
67cb25 |
const double threshold,
|
|
Packit |
67cb25 |
gsl_sf_result * result
|
|
Packit |
67cb25 |
)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* CHECK_POINTER(result) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(nu < 0.0 || x < 0.0) {
|
|
Packit |
67cb25 |
DOMAIN_ERROR(result);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if(x == 0.0) {
|
|
Packit |
67cb25 |
if(nu == 0.0) {
|
|
Packit |
67cb25 |
result->val = 1.0;
|
|
Packit |
67cb25 |
result->err = 0.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
result->val = 0.0;
|
|
Packit |
67cb25 |
result->err = 0.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
gsl_sf_result prefactor; /* (x/2)^nu / Gamma(nu+1) */
|
|
Packit |
67cb25 |
gsl_sf_result sum;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int stat_pre;
|
|
Packit |
67cb25 |
int stat_sum;
|
|
Packit |
67cb25 |
int stat_mul;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(nu == 0.0) {
|
|
Packit |
67cb25 |
prefactor.val = 1.0;
|
|
Packit |
67cb25 |
prefactor.err = 0.0;
|
|
Packit |
67cb25 |
stat_pre = GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if(nu < INT_MAX-1) {
|
|
Packit |
67cb25 |
/* Separate the integer part and use
|
|
Packit |
67cb25 |
* y^nu / Gamma(nu+1) = y^N /N! y^f / (N+1)_f,
|
|
Packit |
67cb25 |
* to control the error.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
const int N = (int)floor(nu + 0.5);
|
|
Packit |
67cb25 |
const double f = nu - N;
|
|
Packit |
67cb25 |
gsl_sf_result poch_factor;
|
|
Packit |
67cb25 |
gsl_sf_result tc_factor;
|
|
Packit |
67cb25 |
const int stat_poch = gsl_sf_poch_e(N+1.0, f, &poch_factor);
|
|
Packit |
67cb25 |
const int stat_tc = gsl_sf_taylorcoeff_e(N, 0.5*x, &tc_factor);
|
|
Packit |
67cb25 |
const double p = pow(0.5*x,f);
|
|
Packit |
67cb25 |
prefactor.val = tc_factor.val * p / poch_factor.val;
|
|
Packit |
67cb25 |
prefactor.err = tc_factor.err * p / poch_factor.val;
|
|
Packit |
67cb25 |
prefactor.err += fabs(prefactor.val) / poch_factor.val * poch_factor.err;
|
|
Packit |
67cb25 |
prefactor.err += 2.0 * GSL_DBL_EPSILON * fabs(prefactor.val);
|
|
Packit |
67cb25 |
stat_pre = GSL_ERROR_SELECT_2(stat_tc, stat_poch);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
gsl_sf_result lg;
|
|
Packit |
67cb25 |
const int stat_lg = gsl_sf_lngamma_e(nu+1.0, &lg);
|
|
Packit |
67cb25 |
const double term1 = nu*log(0.5*x);
|
|
Packit |
67cb25 |
const double term2 = lg.val;
|
|
Packit |
67cb25 |
const double ln_pre = term1 - term2;
|
|
Packit |
67cb25 |
const double ln_pre_err = GSL_DBL_EPSILON * (fabs(term1)+fabs(term2)) + lg.err;
|
|
Packit |
67cb25 |
const int stat_ex = gsl_sf_exp_err_e(ln_pre, ln_pre_err, &prefactor);
|
|
Packit |
67cb25 |
stat_pre = GSL_ERROR_SELECT_2(stat_ex, stat_lg);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Evaluate the sum.
|
|
Packit |
67cb25 |
* [Abramowitz+Stegun, 9.1.10]
|
|
Packit |
67cb25 |
* [Abramowitz+Stegun, 9.6.7]
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const double y = sign * 0.25 * x*x;
|
|
Packit |
67cb25 |
double sumk = 1.0;
|
|
Packit |
67cb25 |
double term = 1.0;
|
|
Packit |
67cb25 |
int k;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for(k=1; k<=kmax; k++) {
|
|
Packit |
67cb25 |
term *= y/((nu+k)*k);
|
|
Packit |
67cb25 |
sumk += term;
|
|
Packit |
67cb25 |
if(fabs(term/sumk) < threshold) break;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
sum.val = sumk;
|
|
Packit |
67cb25 |
sum.err = threshold * fabs(sumk);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
stat_sum = ( k >= kmax ? GSL_EMAXITER : GSL_SUCCESS );
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
stat_mul = gsl_sf_multiply_err_e(prefactor.val, prefactor.err,
|
|
Packit |
67cb25 |
sum.val, sum.err,
|
|
Packit |
67cb25 |
result);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_ERROR_SELECT_3(stat_mul, stat_pre, stat_sum);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Hankel's Asymptotic Expansion - A&S 9.2.5
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* x >> nu*nu+1
|
|
Packit |
67cb25 |
* error ~ O( ((nu*nu+1)/x)^4 )
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* empirical error analysis:
|
|
Packit |
67cb25 |
* choose GSL_ROOT4_MACH_EPS * x > (nu*nu + 1)
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This is not especially useful. When the argument gets
|
|
Packit |
67cb25 |
* large enough for this to apply, the cos() and sin()
|
|
Packit |
67cb25 |
* start loosing digits. However, this seems inevitable
|
|
Packit |
67cb25 |
* for this particular method.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Wed Jun 25 14:39:38 MDT 2003 [GJ]
|
|
Packit |
67cb25 |
* This function was inconsistent since the Q term did not
|
|
Packit |
67cb25 |
* go to relative order eps^2. That's why the error estimate
|
|
Packit |
67cb25 |
* originally given was screwy (it didn't make sense that the
|
|
Packit |
67cb25 |
* "empirical" error was coming out O(eps^3)).
|
|
Packit |
67cb25 |
* With Q to proper order, the error is O(eps^4).
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Sat Mar 15 05:16:18 GMT 2008 [BG]
|
|
Packit |
67cb25 |
* Extended to use additional terms in the series to gain
|
|
Packit |
67cb25 |
* higher accuracy.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_bessel_Jnu_asympx_e(const double nu, const double x, gsl_sf_result * result)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double mu = 4.0*nu*nu;
|
|
Packit |
67cb25 |
double chi = x - (0.5*nu + 0.25)*M_PI;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double P = 0.0;
|
|
Packit |
67cb25 |
double Q = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double k = 0, t = 1;
|
|
Packit |
67cb25 |
int convP, convQ;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
do
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
t *= (k == 0) ? 1 : -(mu - (2*k-1)*(2*k-1)) / (k * (8 * x));
|
|
Packit |
67cb25 |
convP = fabs(t) < GSL_DBL_EPSILON * fabs(P);
|
|
Packit |
67cb25 |
P += t;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
k++;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
t *= (mu - (2*k-1)*(2*k-1)) / (k * (8 * x));
|
|
Packit |
67cb25 |
convQ = fabs(t) < GSL_DBL_EPSILON * fabs(Q);
|
|
Packit |
67cb25 |
Q += t;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* To preserve the consistency of the series we need to exit
|
|
Packit |
67cb25 |
when P and Q have the same number of terms */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (convP && convQ && k > (nu / 2))
|
|
Packit |
67cb25 |
break;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
k++;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
while (k < 1000);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double pre = sqrt(2.0/(M_PI*x));
|
|
Packit |
67cb25 |
double c = cos(chi);
|
|
Packit |
67cb25 |
double s = sin(chi);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result->val = pre * (c*P - s*Q);
|
|
Packit |
67cb25 |
result->err = pre * GSL_DBL_EPSILON * (fabs(c*P) + fabs(s*Q) + fabs(t)) * (1 + fabs(x));
|
|
Packit |
67cb25 |
/* NB: final term accounts for phase error with large x */
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* x >> nu*nu+1
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_bessel_Ynu_asympx_e(const double nu, const double x, gsl_sf_result * result)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double ampl;
|
|
Packit |
67cb25 |
double theta;
|
|
Packit |
67cb25 |
double alpha = x;
|
|
Packit |
67cb25 |
double beta = -0.5*nu*M_PI;
|
|
Packit |
67cb25 |
int stat_a = gsl_sf_bessel_asymp_Mnu_e(nu, x, &l;;
|
|
Packit |
67cb25 |
int stat_t = gsl_sf_bessel_asymp_thetanu_corr_e(nu, x, &theta);
|
|
Packit |
67cb25 |
double sin_alpha = sin(alpha);
|
|
Packit |
67cb25 |
double cos_alpha = cos(alpha);
|
|
Packit |
67cb25 |
double sin_chi = sin(beta + theta);
|
|
Packit |
67cb25 |
double cos_chi = cos(beta + theta);
|
|
Packit |
67cb25 |
double sin_term = sin_alpha * cos_chi + sin_chi * cos_alpha;
|
|
Packit |
67cb25 |
double sin_term_mag = fabs(sin_alpha * cos_chi) + fabs(sin_chi * cos_alpha);
|
|
Packit |
67cb25 |
result->val = ampl * sin_term;
|
|
Packit |
67cb25 |
result->err = fabs(ampl) * GSL_DBL_EPSILON * sin_term_mag;
|
|
Packit |
67cb25 |
result->err += fabs(result->val) * 2.0 * GSL_DBL_EPSILON;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(fabs(alpha) > 1.0/GSL_DBL_EPSILON) {
|
|
Packit |
67cb25 |
result->err *= 0.5 * fabs(alpha);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if(fabs(alpha) > 1.0/GSL_SQRT_DBL_EPSILON) {
|
|
Packit |
67cb25 |
result->err *= 256.0 * fabs(alpha) * GSL_SQRT_DBL_EPSILON;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_ERROR_SELECT_2(stat_t, stat_a);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* x >> nu*nu+1
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_bessel_Inu_scaled_asympx_e(const double nu, const double x, gsl_sf_result * result)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double mu = 4.0*nu*nu;
|
|
Packit |
67cb25 |
double mum1 = mu-1.0;
|
|
Packit |
67cb25 |
double mum9 = mu-9.0;
|
|
Packit |
67cb25 |
double pre = 1.0/sqrt(2.0*M_PI*x);
|
|
Packit |
67cb25 |
double r = mu/x;
|
|
Packit |
67cb25 |
result->val = pre * (1.0 - mum1/(8.0*x) + mum1*mum9/(128.0*x*x));
|
|
Packit |
67cb25 |
result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val) + pre * fabs(0.1*r*r*r);
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* x >> nu*nu+1
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_bessel_Knu_scaled_asympx_e(const double nu, const double x, gsl_sf_result * result)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double mu = 4.0*nu*nu;
|
|
Packit |
67cb25 |
double mum1 = mu-1.0;
|
|
Packit |
67cb25 |
double mum9 = mu-9.0;
|
|
Packit |
67cb25 |
double pre = sqrt(M_PI/(2.0*x));
|
|
Packit |
67cb25 |
double r = nu/x;
|
|
Packit |
67cb25 |
result->val = pre * (1.0 + mum1/(8.0*x) + mum1*mum9/(128.0*x*x));
|
|
Packit |
67cb25 |
result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val) + pre * fabs(0.1*r*r*r);
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* nu -> Inf; uniform in x > 0 [Abramowitz+Stegun, 9.7.7]
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* error:
|
|
Packit |
67cb25 |
* The error has the form u_N(t)/nu^N where 0 <= t <= 1.
|
|
Packit |
67cb25 |
* It is not hard to show that |u_N(t)| is small for such t.
|
|
Packit |
67cb25 |
* We have N=6 here, and |u_6(t)| < 0.025, so the error is clearly
|
|
Packit |
67cb25 |
* bounded by 0.025/nu^6. This gives the asymptotic bound on nu
|
|
Packit |
67cb25 |
* seen below as nu ~ 100. For general MACH_EPS it will be
|
|
Packit |
67cb25 |
* nu > 0.5 / MACH_EPS^(1/6)
|
|
Packit |
67cb25 |
* When t is small, the bound is even better because |u_N(t)| vanishes
|
|
Packit |
67cb25 |
* as t->0. In fact u_N(t) ~ C t^N as t->0, with C ~= 0.1.
|
|
Packit |
67cb25 |
* We write
|
|
Packit |
67cb25 |
* err_N <= min(0.025, C(1/(1+(x/nu)^2))^3) / nu^6
|
|
Packit |
67cb25 |
* therefore
|
|
Packit |
67cb25 |
* min(0.29/nu^2, 0.5/(nu^2+x^2)) < MACH_EPS^{1/3}
|
|
Packit |
67cb25 |
* and this is the general form.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* empirical error analysis, assuming 14 digit requirement:
|
|
Packit |
67cb25 |
* choose x > 50.000 nu ==> nu > 3
|
|
Packit |
67cb25 |
* choose x > 10.000 nu ==> nu > 15
|
|
Packit |
67cb25 |
* choose x > 2.000 nu ==> nu > 50
|
|
Packit |
67cb25 |
* choose x > 1.000 nu ==> nu > 75
|
|
Packit |
67cb25 |
* choose x > 0.500 nu ==> nu > 80
|
|
Packit |
67cb25 |
* choose x > 0.100 nu ==> nu > 83
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This makes sense. For x << nu, the error will be of the form u_N(1)/nu^N,
|
|
Packit |
67cb25 |
* since the polynomial term will be evaluated near t=1, so the bound
|
|
Packit |
67cb25 |
* on nu will become constant for small x. Furthermore, increasing x with
|
|
Packit |
67cb25 |
* nu fixed will decrease the error.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_bessel_Inu_scaled_asymp_unif_e(const double nu, const double x, gsl_sf_result * result)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int i;
|
|
Packit |
67cb25 |
double z = x/nu;
|
|
Packit |
67cb25 |
double root_term = hypot(1.0,z);
|
|
Packit |
67cb25 |
double pre = 1.0/sqrt(2.0*M_PI*nu * root_term);
|
|
Packit |
67cb25 |
double eta = root_term + log(z/(1.0+root_term));
|
|
Packit |
67cb25 |
double ex_arg = ( z < 1.0/GSL_ROOT3_DBL_EPSILON ? nu*(-z + eta) : -0.5*nu/z*(1.0 - 1.0/(12.0*z*z)) );
|
|
Packit |
67cb25 |
gsl_sf_result ex_result;
|
|
Packit |
67cb25 |
int stat_ex = gsl_sf_exp_e(ex_arg, &ex_result);
|
|
Packit |
67cb25 |
if(stat_ex == GSL_SUCCESS) {
|
|
Packit |
67cb25 |
double t = 1.0/root_term;
|
|
Packit |
67cb25 |
double sum;
|
|
Packit |
67cb25 |
double tpow[16];
|
|
Packit |
67cb25 |
tpow[0] = 1.0;
|
|
Packit |
67cb25 |
for(i=1; i<16; i++) tpow[i] = t * tpow[i-1];
|
|
Packit |
67cb25 |
sum = 1.0 + debye_u1(tpow)/nu + debye_u2(tpow)/(nu*nu) + debye_u3(tpow)/(nu*nu*nu)
|
|
Packit |
67cb25 |
+ debye_u4(tpow)/(nu*nu*nu*nu) + debye_u5(tpow)/(nu*nu*nu*nu*nu);
|
|
Packit |
67cb25 |
result->val = pre * ex_result.val * sum;
|
|
Packit |
67cb25 |
result->err = pre * ex_result.val / (nu*nu*nu*nu*nu*nu);
|
|
Packit |
67cb25 |
result->err += pre * ex_result.err * fabs(sum);
|
|
Packit |
67cb25 |
result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
result->val = 0.0;
|
|
Packit |
67cb25 |
result->err = 0.0;
|
|
Packit |
67cb25 |
return stat_ex;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* nu -> Inf; uniform in x > 0 [Abramowitz+Stegun, 9.7.8]
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* error:
|
|
Packit |
67cb25 |
* identical to that above for Inu_scaled
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_bessel_Knu_scaled_asymp_unif_e(const double nu, const double x, gsl_sf_result * result)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int i;
|
|
Packit |
67cb25 |
double z = x/nu;
|
|
Packit |
67cb25 |
double root_term = hypot(1.0,z);
|
|
Packit |
67cb25 |
double pre = sqrt(M_PI/(2.0*nu*root_term));
|
|
Packit |
67cb25 |
double eta = root_term + log(z/(1.0+root_term));
|
|
Packit |
67cb25 |
double ex_arg = ( z < 1.0/GSL_ROOT3_DBL_EPSILON ? nu*(z - eta) : 0.5*nu/z*(1.0 + 1.0/(12.0*z*z)) );
|
|
Packit |
67cb25 |
gsl_sf_result ex_result;
|
|
Packit |
67cb25 |
int stat_ex = gsl_sf_exp_e(ex_arg, &ex_result);
|
|
Packit |
67cb25 |
if(stat_ex == GSL_SUCCESS) {
|
|
Packit |
67cb25 |
double t = 1.0/root_term;
|
|
Packit |
67cb25 |
double sum;
|
|
Packit |
67cb25 |
double tpow[16];
|
|
Packit |
67cb25 |
tpow[0] = 1.0;
|
|
Packit |
67cb25 |
for(i=1; i<16; i++) tpow[i] = t * tpow[i-1];
|
|
Packit |
67cb25 |
sum = 1.0 - debye_u1(tpow)/nu + debye_u2(tpow)/(nu*nu) - debye_u3(tpow)/(nu*nu*nu)
|
|
Packit |
67cb25 |
+ debye_u4(tpow)/(nu*nu*nu*nu) - debye_u5(tpow)/(nu*nu*nu*nu*nu);
|
|
Packit |
67cb25 |
result->val = pre * ex_result.val * sum;
|
|
Packit |
67cb25 |
result->err = pre * ex_result.err * fabs(sum);
|
|
Packit |
67cb25 |
result->err += pre * ex_result.val / (nu*nu*nu*nu*nu*nu);
|
|
Packit |
67cb25 |
result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
result->val = 0.0;
|
|
Packit |
67cb25 |
result->err = 0.0;
|
|
Packit |
67cb25 |
return stat_ex;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Evaluate J_mu(x),J_{mu+1}(x) and Y_mu(x),Y_{mu+1}(x) for |mu| < 1/2
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_bessel_JY_mu_restricted(const double mu, const double x,
|
|
Packit |
67cb25 |
gsl_sf_result * Jmu, gsl_sf_result * Jmup1,
|
|
Packit |
67cb25 |
gsl_sf_result * Ymu, gsl_sf_result * Ymup1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* CHECK_POINTER(Jmu) */
|
|
Packit |
67cb25 |
/* CHECK_POINTER(Jmup1) */
|
|
Packit |
67cb25 |
/* CHECK_POINTER(Ymu) */
|
|
Packit |
67cb25 |
/* CHECK_POINTER(Ymup1) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(x < 0.0 || fabs(mu) > 0.5) {
|
|
Packit |
67cb25 |
Jmu->val = 0.0;
|
|
Packit |
67cb25 |
Jmu->err = 0.0;
|
|
Packit |
67cb25 |
Jmup1->val = 0.0;
|
|
Packit |
67cb25 |
Jmup1->err = 0.0;
|
|
Packit |
67cb25 |
Ymu->val = 0.0;
|
|
Packit |
67cb25 |
Ymu->err = 0.0;
|
|
Packit |
67cb25 |
Ymup1->val = 0.0;
|
|
Packit |
67cb25 |
Ymup1->err = 0.0;
|
|
Packit |
67cb25 |
GSL_ERROR ("error", GSL_EDOM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if(x == 0.0) {
|
|
Packit |
67cb25 |
if(mu == 0.0) {
|
|
Packit |
67cb25 |
Jmu->val = 1.0;
|
|
Packit |
67cb25 |
Jmu->err = 0.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
Jmu->val = 0.0;
|
|
Packit |
67cb25 |
Jmu->err = 0.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
Jmup1->val = 0.0;
|
|
Packit |
67cb25 |
Jmup1->err = 0.0;
|
|
Packit |
67cb25 |
Ymu->val = 0.0;
|
|
Packit |
67cb25 |
Ymu->err = 0.0;
|
|
Packit |
67cb25 |
Ymup1->val = 0.0;
|
|
Packit |
67cb25 |
Ymup1->err = 0.0;
|
|
Packit |
67cb25 |
GSL_ERROR ("error", GSL_EDOM);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
int stat_Y;
|
|
Packit |
67cb25 |
int stat_J;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(x < 2.0) {
|
|
Packit |
67cb25 |
/* Use Taylor series for J and the Temme series for Y.
|
|
Packit |
67cb25 |
* The Taylor series for J requires nu > 0, so we shift
|
|
Packit |
67cb25 |
* up one and use the recursion relation to get Jmu, in
|
|
Packit |
67cb25 |
* case mu < 0.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
gsl_sf_result Jmup2;
|
|
Packit |
67cb25 |
int stat_J1 = gsl_sf_bessel_IJ_taylor_e(mu+1.0, x, -1, 100, GSL_DBL_EPSILON, Jmup1);
|
|
Packit |
67cb25 |
int stat_J2 = gsl_sf_bessel_IJ_taylor_e(mu+2.0, x, -1, 100, GSL_DBL_EPSILON, &Jmup2);
|
|
Packit |
67cb25 |
double c = 2.0*(mu+1.0)/x;
|
|
Packit |
67cb25 |
Jmu->val = c * Jmup1->val - Jmup2.val;
|
|
Packit |
67cb25 |
Jmu->err = c * Jmup1->err + Jmup2.err;
|
|
Packit |
67cb25 |
Jmu->err += 2.0 * GSL_DBL_EPSILON * fabs(Jmu->val);
|
|
Packit |
67cb25 |
stat_J = GSL_ERROR_SELECT_2(stat_J1, stat_J2);
|
|
Packit |
67cb25 |
stat_Y = gsl_sf_bessel_Y_temme(mu, x, Ymu, Ymup1);
|
|
Packit |
67cb25 |
return GSL_ERROR_SELECT_2(stat_J, stat_Y);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if(x < 1000.0) {
|
|
Packit |
67cb25 |
double P, Q;
|
|
Packit |
67cb25 |
double J_ratio;
|
|
Packit |
67cb25 |
double J_sgn;
|
|
Packit |
67cb25 |
const int stat_CF1 = gsl_sf_bessel_J_CF1(mu, x, &J_ratio, &J_sgn);
|
|
Packit |
67cb25 |
const int stat_CF2 = gsl_sf_bessel_JY_steed_CF2(mu, x, &P, &Q);
|
|
Packit |
67cb25 |
double Jprime_J_ratio = mu/x - J_ratio;
|
|
Packit |
67cb25 |
double gamma = (P - Jprime_J_ratio)/Q;
|
|
Packit |
67cb25 |
Jmu->val = J_sgn * sqrt(2.0/(M_PI*x) / (Q + gamma*(P-Jprime_J_ratio)));
|
|
Packit |
67cb25 |
Jmu->err = 4.0 * GSL_DBL_EPSILON * fabs(Jmu->val);
|
|
Packit |
67cb25 |
Jmup1->val = J_ratio * Jmu->val;
|
|
Packit |
67cb25 |
Jmup1->err = fabs(J_ratio) * Jmu->err;
|
|
Packit |
67cb25 |
Ymu->val = gamma * Jmu->val;
|
|
Packit |
67cb25 |
Ymu->err = fabs(gamma) * Jmu->err;
|
|
Packit |
67cb25 |
Ymup1->val = Ymu->val * (mu/x - P - Q/gamma);
|
|
Packit |
67cb25 |
Ymup1->err = Ymu->err * fabs(mu/x - P - Q/gamma) + 4.0*GSL_DBL_EPSILON*fabs(Ymup1->val);
|
|
Packit |
67cb25 |
return GSL_ERROR_SELECT_2(stat_CF1, stat_CF2);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
/* Use asymptotics for large argument.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
const int stat_J0 = gsl_sf_bessel_Jnu_asympx_e(mu, x, Jmu);
|
|
Packit |
67cb25 |
const int stat_J1 = gsl_sf_bessel_Jnu_asympx_e(mu+1.0, x, Jmup1);
|
|
Packit |
67cb25 |
const int stat_Y0 = gsl_sf_bessel_Ynu_asympx_e(mu, x, Ymu);
|
|
Packit |
67cb25 |
const int stat_Y1 = gsl_sf_bessel_Ynu_asympx_e(mu+1.0, x, Ymup1);
|
|
Packit |
67cb25 |
stat_J = GSL_ERROR_SELECT_2(stat_J0, stat_J1);
|
|
Packit |
67cb25 |
stat_Y = GSL_ERROR_SELECT_2(stat_Y0, stat_Y1);
|
|
Packit |
67cb25 |
return GSL_ERROR_SELECT_2(stat_J, stat_Y);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_bessel_J_CF1(const double nu, const double x,
|
|
Packit |
67cb25 |
double * ratio, double * sgn)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const double RECUR_BIG = GSL_SQRT_DBL_MAX;
|
|
Packit |
67cb25 |
const double RECUR_SMALL = GSL_SQRT_DBL_MIN;
|
|
Packit |
67cb25 |
const int maxiter = 10000;
|
|
Packit |
67cb25 |
int n = 1;
|
|
Packit |
67cb25 |
double Anm2 = 1.0;
|
|
Packit |
67cb25 |
double Bnm2 = 0.0;
|
|
Packit |
67cb25 |
double Anm1 = 0.0;
|
|
Packit |
67cb25 |
double Bnm1 = 1.0;
|
|
Packit |
67cb25 |
double a1 = x/(2.0*(nu+1.0));
|
|
Packit |
67cb25 |
double An = Anm1 + a1*Anm2;
|
|
Packit |
67cb25 |
double Bn = Bnm1 + a1*Bnm2;
|
|
Packit |
67cb25 |
double an;
|
|
Packit |
67cb25 |
double fn = An/Bn;
|
|
Packit |
67cb25 |
double dn = a1;
|
|
Packit |
67cb25 |
double s = 1.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
while(n < maxiter) {
|
|
Packit |
67cb25 |
double old_fn;
|
|
Packit |
67cb25 |
double del;
|
|
Packit |
67cb25 |
n++;
|
|
Packit |
67cb25 |
Anm2 = Anm1;
|
|
Packit |
67cb25 |
Bnm2 = Bnm1;
|
|
Packit |
67cb25 |
Anm1 = An;
|
|
Packit |
67cb25 |
Bnm1 = Bn;
|
|
Packit |
67cb25 |
an = -x*x/(4.0*(nu+n-1.0)*(nu+n));
|
|
Packit |
67cb25 |
An = Anm1 + an*Anm2;
|
|
Packit |
67cb25 |
Bn = Bnm1 + an*Bnm2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(fabs(An) > RECUR_BIG || fabs(Bn) > RECUR_BIG) {
|
|
Packit |
67cb25 |
An /= RECUR_BIG;
|
|
Packit |
67cb25 |
Bn /= RECUR_BIG;
|
|
Packit |
67cb25 |
Anm1 /= RECUR_BIG;
|
|
Packit |
67cb25 |
Bnm1 /= RECUR_BIG;
|
|
Packit |
67cb25 |
Anm2 /= RECUR_BIG;
|
|
Packit |
67cb25 |
} else if(fabs(An) < RECUR_SMALL || fabs(Bn) < RECUR_SMALL) {
|
|
Packit |
67cb25 |
An /= RECUR_SMALL;
|
|
Packit |
67cb25 |
Bn /= RECUR_SMALL;
|
|
Packit |
67cb25 |
Anm1 /= RECUR_SMALL;
|
|
Packit |
67cb25 |
Bnm1 /= RECUR_SMALL;
|
|
Packit |
67cb25 |
Anm2 /= RECUR_SMALL;
|
|
Packit |
67cb25 |
Bnm2 /= RECUR_SMALL;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
old_fn = fn;
|
|
Packit |
67cb25 |
fn = An/Bn;
|
|
Packit |
67cb25 |
del = old_fn/fn;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
dn = 1.0 / (2.0*(nu+n)/x - dn);
|
|
Packit |
67cb25 |
if(dn < 0.0) s = -s;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(fabs(del - 1.0) < 2.0*GSL_DBL_EPSILON) break;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* FIXME: we should return an error term here as well, because the
|
|
Packit |
67cb25 |
error from this recurrence affects the overall error estimate. */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*ratio = fn;
|
|
Packit |
67cb25 |
*sgn = s;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(n >= maxiter)
|
|
Packit |
67cb25 |
GSL_ERROR ("error", GSL_EMAXITER);
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Evaluate the continued fraction CF1 for J_{nu+1}/J_nu
|
|
Packit |
67cb25 |
* using Gautschi (Euler) equivalent series.
|
|
Packit |
67cb25 |
* This exhibits an annoying problem because the
|
|
Packit |
67cb25 |
* a_k are not positive definite (in fact they are all negative).
|
|
Packit |
67cb25 |
* There are cases when rho_k blows up. Example: nu=1,x=4.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
#if 0
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_bessel_J_CF1_ser(const double nu, const double x,
|
|
Packit |
67cb25 |
double * ratio, double * sgn)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const int maxk = 20000;
|
|
Packit |
67cb25 |
double tk = 1.0;
|
|
Packit |
67cb25 |
double sum = 1.0;
|
|
Packit |
67cb25 |
double rhok = 0.0;
|
|
Packit |
67cb25 |
double dk = 0.0;
|
|
Packit |
67cb25 |
double s = 1.0;
|
|
Packit |
67cb25 |
int k;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for(k=1; k
|
|
Packit |
67cb25 |
double ak = -0.25 * (x/(nu+k)) * x/(nu+k+1.0);
|
|
Packit |
67cb25 |
rhok = -ak*(1.0 + rhok)/(1.0 + ak*(1.0 + rhok));
|
|
Packit |
67cb25 |
tk *= rhok;
|
|
Packit |
67cb25 |
sum += tk;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
dk = 1.0 / (2.0/x - (nu+k-1.0)/(nu+k) * dk);
|
|
Packit |
67cb25 |
if(dk < 0.0) s = -s;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(fabs(tk/sum) < GSL_DBL_EPSILON) break;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*ratio = x/(2.0*(nu+1.0)) * sum;
|
|
Packit |
67cb25 |
*sgn = s;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(k == maxk)
|
|
Packit |
67cb25 |
GSL_ERROR ("error", GSL_EMAXITER);
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Evaluate the continued fraction CF1 for I_{nu+1}/I_nu
|
|
Packit |
67cb25 |
* using Gautschi (Euler) equivalent series.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_bessel_I_CF1_ser(const double nu, const double x, double * ratio)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const int maxk = 20000;
|
|
Packit |
67cb25 |
double tk = 1.0;
|
|
Packit |
67cb25 |
double sum = 1.0;
|
|
Packit |
67cb25 |
double rhok = 0.0;
|
|
Packit |
67cb25 |
int k;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for(k=1; k
|
|
Packit |
67cb25 |
double ak = 0.25 * (x/(nu+k)) * x/(nu+k+1.0);
|
|
Packit |
67cb25 |
rhok = -ak*(1.0 + rhok)/(1.0 + ak*(1.0 + rhok));
|
|
Packit |
67cb25 |
tk *= rhok;
|
|
Packit |
67cb25 |
sum += tk;
|
|
Packit |
67cb25 |
if(fabs(tk/sum) < GSL_DBL_EPSILON) break;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*ratio = x/(2.0*(nu+1.0)) * sum;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(k == maxk)
|
|
Packit |
67cb25 |
GSL_ERROR ("error", GSL_EMAXITER);
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_bessel_JY_steed_CF2(const double nu, const double x,
|
|
Packit |
67cb25 |
double * P, double * Q)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const int max_iter = 10000;
|
|
Packit |
67cb25 |
const double SMALL = 1.0e-100;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int i = 1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double x_inv = 1.0/x;
|
|
Packit |
67cb25 |
double a = 0.25 - nu*nu;
|
|
Packit |
67cb25 |
double p = -0.5*x_inv;
|
|
Packit |
67cb25 |
double q = 1.0;
|
|
Packit |
67cb25 |
double br = 2.0*x;
|
|
Packit |
67cb25 |
double bi = 2.0;
|
|
Packit |
67cb25 |
double fact = a*x_inv/(p*p + q*q);
|
|
Packit |
67cb25 |
double cr = br + q*fact;
|
|
Packit |
67cb25 |
double ci = bi + p*fact;
|
|
Packit |
67cb25 |
double den = br*br + bi*bi;
|
|
Packit |
67cb25 |
double dr = br/den;
|
|
Packit |
67cb25 |
double di = -bi/den;
|
|
Packit |
67cb25 |
double dlr = cr*dr - ci*di;
|
|
Packit |
67cb25 |
double dli = cr*di + ci*dr;
|
|
Packit |
67cb25 |
double temp = p*dlr - q*dli;
|
|
Packit |
67cb25 |
q = p*dli + q*dlr;
|
|
Packit |
67cb25 |
p = temp;
|
|
Packit |
67cb25 |
for (i=2; i<=max_iter; i++) {
|
|
Packit |
67cb25 |
a += 2*(i-1);
|
|
Packit |
67cb25 |
bi += 2.0;
|
|
Packit |
67cb25 |
dr = a*dr + br;
|
|
Packit |
67cb25 |
di = a*di + bi;
|
|
Packit |
67cb25 |
if(fabs(dr)+fabs(di) < SMALL) dr = SMALL;
|
|
Packit |
67cb25 |
fact = a/(cr*cr+ci*ci);
|
|
Packit |
67cb25 |
cr = br + cr*fact;
|
|
Packit |
67cb25 |
ci = bi - ci*fact;
|
|
Packit |
67cb25 |
if(fabs(cr)+fabs(ci) < SMALL) cr = SMALL;
|
|
Packit |
67cb25 |
den = dr*dr + di*di;
|
|
Packit |
67cb25 |
dr /= den;
|
|
Packit |
67cb25 |
di /= -den;
|
|
Packit |
67cb25 |
dlr = cr*dr - ci*di;
|
|
Packit |
67cb25 |
dli = cr*di + ci*dr;
|
|
Packit |
67cb25 |
temp = p*dlr - q*dli;
|
|
Packit |
67cb25 |
q = p*dli + q*dlr;
|
|
Packit |
67cb25 |
p = temp;
|
|
Packit |
67cb25 |
if(fabs(dlr-1.0)+fabs(dli) < GSL_DBL_EPSILON) break;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*P = p;
|
|
Packit |
67cb25 |
*Q = q;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if(i == max_iter)
|
|
Packit |
67cb25 |
GSL_ERROR ("error", GSL_EMAXITER);
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Evaluate continued fraction CF2, using Thompson-Barnett-Temme method,
|
|
Packit |
67cb25 |
* to obtain values of exp(x)*K_nu and exp(x)*K_{nu+1}.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This is unstable for small x; x > 2 is a good cutoff.
|
|
Packit |
67cb25 |
* Also requires |nu| < 1/2.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_sf_bessel_K_scaled_steed_temme_CF2(const double nu, const double x,
|
|
Packit |
67cb25 |
double * K_nu, double * K_nup1,
|
|
Packit |
67cb25 |
double * Kp_nu)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const int maxiter = 10000;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int i = 1;
|
|
Packit |
67cb25 |
double bi = 2.0*(1.0 + x);
|
|
Packit |
67cb25 |
double di = 1.0/bi;
|
|
Packit |
67cb25 |
double delhi = di;
|
|
Packit |
67cb25 |
double hi = di;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double qi = 0.0;
|
|
Packit |
67cb25 |
double qip1 = 1.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double ai = -(0.25 - nu*nu);
|
|
Packit |
67cb25 |
double a1 = ai;
|
|
Packit |
67cb25 |
double ci = -ai;
|
|
Packit |
67cb25 |
double Qi = -ai;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double s = 1.0 + Qi*delhi;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for(i=2; i<=maxiter; i++) {
|
|
Packit |
67cb25 |
double dels;
|
|
Packit |
67cb25 |
double tmp;
|
|
Packit |
67cb25 |
ai -= 2.0*(i-1);
|
|
Packit |
67cb25 |
ci = -ai*ci/i;
|
|
Packit |
67cb25 |
tmp = (qi - bi*qip1)/ai;
|
|
Packit |
67cb25 |
qi = qip1;
|
|
Packit |
67cb25 |
qip1 = tmp;
|
|
Packit |
67cb25 |
Qi += ci*qip1;
|
|
Packit |
67cb25 |
bi += 2.0;
|
|
Packit |
67cb25 |
di = 1.0/(bi + ai*di);
|
|
Packit |
67cb25 |
delhi = (bi*di - 1.0) * delhi;
|
|
Packit |
67cb25 |
hi += delhi;
|
|
Packit |
67cb25 |
dels = Qi*delhi;
|
|
Packit |
67cb25 |
s += dels;
|
|
Packit |
67cb25 |
if(fabs(dels/s) < GSL_DBL_EPSILON) break;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
hi *= -a1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*K_nu = sqrt(M_PI/(2.0*x)) / s;
|
|
Packit |
67cb25 |
*K_nup1 = *K_nu * (nu + x + 0.5 - hi)/x;
|
|
Packit |
67cb25 |
*Kp_nu = - *K_nup1 + nu/x * *K_nu;
|
|
Packit |
67cb25 |
if(i == maxiter)
|
|
Packit |
67cb25 |
GSL_ERROR ("error", GSL_EMAXITER);
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int gsl_sf_bessel_cos_pi4_e(double y, double eps, gsl_sf_result * result)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const double sy = sin(y);
|
|
Packit |
67cb25 |
const double cy = cos(y);
|
|
Packit |
67cb25 |
const double s = sy + cy;
|
|
Packit |
67cb25 |
const double d = sy - cy;
|
|
Packit |
67cb25 |
const double abs_sum = fabs(cy) + fabs(sy);
|
|
Packit |
67cb25 |
double seps;
|
|
Packit |
67cb25 |
double ceps;
|
|
Packit |
67cb25 |
if(fabs(eps) < GSL_ROOT5_DBL_EPSILON) {
|
|
Packit |
67cb25 |
const double e2 = eps*eps;
|
|
Packit |
67cb25 |
seps = eps * (1.0 - e2/6.0 * (1.0 - e2/20.0));
|
|
Packit |
67cb25 |
ceps = 1.0 - e2/2.0 * (1.0 - e2/12.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
seps = sin(eps);
|
|
Packit |
67cb25 |
ceps = cos(eps);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
result->val = (ceps * s - seps * d)/ M_SQRT2;
|
|
Packit |
67cb25 |
result->err = 2.0 * GSL_DBL_EPSILON * (fabs(ceps) + fabs(seps)) * abs_sum / M_SQRT2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Try to account for error in evaluation of sin(y), cos(y).
|
|
Packit |
67cb25 |
* This is a little sticky because we don't really know
|
|
Packit |
67cb25 |
* how the library routines are doing their argument reduction.
|
|
Packit |
67cb25 |
* However, we will make a reasonable guess.
|
|
Packit |
67cb25 |
* FIXME ?
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
if(y > 1.0/GSL_DBL_EPSILON) {
|
|
Packit |
67cb25 |
result->err *= 0.5 * y;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if(y > 1.0/GSL_SQRT_DBL_EPSILON) {
|
|
Packit |
67cb25 |
result->err *= 256.0 * y * GSL_SQRT_DBL_EPSILON;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int gsl_sf_bessel_sin_pi4_e(double y, double eps, gsl_sf_result * result)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const double sy = sin(y);
|
|
Packit |
67cb25 |
const double cy = cos(y);
|
|
Packit |
67cb25 |
const double s = sy + cy;
|
|
Packit |
67cb25 |
const double d = sy - cy;
|
|
Packit |
67cb25 |
const double abs_sum = fabs(cy) + fabs(sy);
|
|
Packit |
67cb25 |
double seps;
|
|
Packit |
67cb25 |
double ceps;
|
|
Packit |
67cb25 |
if(fabs(eps) < GSL_ROOT5_DBL_EPSILON) {
|
|
Packit |
67cb25 |
const double e2 = eps*eps;
|
|
Packit |
67cb25 |
seps = eps * (1.0 - e2/6.0 * (1.0 - e2/20.0));
|
|
Packit |
67cb25 |
ceps = 1.0 - e2/2.0 * (1.0 - e2/12.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else {
|
|
Packit |
67cb25 |
seps = sin(eps);
|
|
Packit |
67cb25 |
ceps = cos(eps);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
result->val = (ceps * d + seps * s)/ M_SQRT2;
|
|
Packit |
67cb25 |
result->err = 2.0 * GSL_DBL_EPSILON * (fabs(ceps) + fabs(seps)) * abs_sum / M_SQRT2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Try to account for error in evaluation of sin(y), cos(y).
|
|
Packit |
67cb25 |
* See above.
|
|
Packit |
67cb25 |
* FIXME ?
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
if(y > 1.0/GSL_DBL_EPSILON) {
|
|
Packit |
67cb25 |
result->err *= 0.5 * y;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if(y > 1.0/GSL_SQRT_DBL_EPSILON) {
|
|
Packit |
67cb25 |
result->err *= 256.0 * y * GSL_SQRT_DBL_EPSILON;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/************************************************************************
|
|
Packit |
67cb25 |
* *
|
|
Packit |
67cb25 |
Asymptotic approximations 8.11.5, 8.12.5, and 8.42.7 from
|
|
Packit |
67cb25 |
G.N.Watson, A Treatise on the Theory of Bessel Functions,
|
|
Packit |
67cb25 |
2nd Edition (Cambridge University Press, 1944).
|
|
Packit |
67cb25 |
Higher terms in expansion for x near l given by
|
|
Packit |
67cb25 |
Airey in Phil. Mag. 31, 520 (1916).
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
This approximation is accurate to near 0.1% at the boundaries
|
|
Packit |
67cb25 |
between the asymptotic regions; well away from the boundaries
|
|
Packit |
67cb25 |
the accuracy is better than 10^{-5}.
|
|
Packit |
67cb25 |
* *
|
|
Packit |
67cb25 |
************************************************************************/
|
|
Packit |
67cb25 |
#if 0
|
|
Packit |
67cb25 |
double besselJ_meissel(double nu, double x)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double beta = pow(nu, 0.325);
|
|
Packit |
67cb25 |
double result;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Fitted matching points. */
|
|
Packit |
67cb25 |
double llimit = 1.1 * beta;
|
|
Packit |
67cb25 |
double ulimit = 1.3 * beta;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double nu2 = nu * nu;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (nu < 5. && x < 1.)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* Small argument and order. Use a Taylor expansion. */
|
|
Packit |
67cb25 |
int k;
|
|
Packit |
67cb25 |
double xo2 = 0.5 * x;
|
|
Packit |
67cb25 |
double gamfactor = pow(nu,nu) * exp(-nu) * sqrt(nu * 2. * M_PI)
|
|
Packit |
67cb25 |
* (1. + 1./(12.*nu) + 1./(288.*nu*nu));
|
|
Packit |
67cb25 |
double prefactor = pow(xo2, nu) / gamfactor;
|
|
Packit |
67cb25 |
double C[5];
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
C[0] = 1.;
|
|
Packit |
67cb25 |
C[1] = -C[0] / (nu+1.);
|
|
Packit |
67cb25 |
C[2] = -C[1] / (2.*(nu+2.));
|
|
Packit |
67cb25 |
C[3] = -C[2] / (3.*(nu+3.));
|
|
Packit |
67cb25 |
C[4] = -C[3] / (4.*(nu+4.));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result = 0.;
|
|
Packit |
67cb25 |
for(k=0; k<5; k++)
|
|
Packit |
67cb25 |
result += C[k] * pow(xo2, 2.*k);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result *= prefactor;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if(x < nu - llimit)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* Small x region: x << l. */
|
|
Packit |
67cb25 |
double z = x / nu;
|
|
Packit |
67cb25 |
double z2 = z*z;
|
|
Packit |
67cb25 |
double rtomz2 = sqrt(1.-z2);
|
|
Packit |
67cb25 |
double omz2_2 = (1.-z2)*(1.-z2);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Calculate Meissel exponent. */
|
|
Packit |
67cb25 |
double term1 = 1./(24.*nu) * ((2.+3.*z2)/((1.-z2)*rtomz2) -2.);
|
|
Packit |
67cb25 |
double term2 = - z2*(4. + z2)/(16.*nu2*(1.-z2)*omz2_2);
|
|
Packit |
67cb25 |
double V_nu = term1 + term2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Calculate the harmless prefactor. */
|
|
Packit |
67cb25 |
double sterlingsum = 1. + 1./(12.*nu) + 1./(288*nu2);
|
|
Packit |
67cb25 |
double harmless = 1. / (sqrt(rtomz2*2.*M_PI*nu) * sterlingsum);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Calculate the logarithm of the nu dependent prefactor. */
|
|
Packit |
67cb25 |
double ln_nupre = rtomz2 + log(z) - log(1. + rtomz2);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result = harmless * exp(nu*ln_nupre - V_nu);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if(x < nu + ulimit)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* Intermediate region 1: x near nu. */
|
|
Packit |
67cb25 |
double eps = 1.-nu/x;
|
|
Packit |
67cb25 |
double eps_x = eps * x;
|
|
Packit |
67cb25 |
double eps_x_2 = eps_x * eps_x;
|
|
Packit |
67cb25 |
double xo6 = x/6.;
|
|
Packit |
67cb25 |
double B[6];
|
|
Packit |
67cb25 |
static double gam[6] = {2.67894, 1.35412, 1., 0.89298, 0.902745, 1.};
|
|
Packit |
67cb25 |
static double sf[6] = {0.866025, 0.866025, 0., -0.866025, -0.866025, 0.};
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Some terms are identically zero, because sf[] can be zero.
|
|
Packit |
67cb25 |
* Some terms do not appear in the result.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
B[0] = 1.;
|
|
Packit |
67cb25 |
B[1] = eps_x;
|
|
Packit |
67cb25 |
/* B[2] = 0.5 * eps_x_2 - 1./20.; */
|
|
Packit |
67cb25 |
B[3] = eps_x * (eps_x_2/6. - 1./15.);
|
|
Packit |
67cb25 |
B[4] = eps_x_2 * (eps_x_2 - 1.)/24. + 1./280.;
|
|
Packit |
67cb25 |
/* B[5] = eps_x * (eps_x_2*(0.5*eps_x_2 - 1.)/60. + 43./8400.); */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result = B[0] * gam[0] * sf[0] / pow(xo6, 1./3.);
|
|
Packit |
67cb25 |
result += B[1] * gam[1] * sf[1] / pow(xo6, 2./3.);
|
|
Packit |
67cb25 |
result += B[3] * gam[3] * sf[3] / pow(xo6, 4./3.);
|
|
Packit |
67cb25 |
result += B[4] * gam[4] * sf[4] / pow(xo6, 5./3.);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result /= (3.*M_PI);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* Region of very large argument. Use expansion
|
|
Packit |
67cb25 |
* for x>>l, and we need not be very exacting.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
double secb = x/nu;
|
|
Packit |
67cb25 |
double sec2b= secb*secb;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double cotb = 1./sqrt(sec2b-1.); /* cotb=cot(beta) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double beta = acos(nu/x);
|
|
Packit |
67cb25 |
double trigarg = nu/cotb - nu*beta - 0.25 * M_PI;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double cot3b = cotb * cotb * cotb;
|
|
Packit |
67cb25 |
double cot6b = cot3b * cot3b;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double sum1, sum2, expterm, prefactor, trigcos;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
sum1 = 2.0 + 3.0 * sec2b;
|
|
Packit |
67cb25 |
trigarg -= sum1 * cot3b / (24.0 * nu);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
trigcos = cos(trigarg);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
sum2 = 4.0 + sec2b;
|
|
Packit |
67cb25 |
expterm = sum2 * sec2b * cot6b / (16.0 * nu2);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
expterm = exp(-expterm);
|
|
Packit |
67cb25 |
prefactor = sqrt(2. * cotb / (nu * M_PI));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
result = prefactor * expterm * trigcos;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return result;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
#endif
|