/* specfunc/bessel_K0.c * * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman * Copyright (C) 2016 Pavel Holoborodko, Patrick Alken * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Author: G. Jungman */ #include #include #include #include #include #include #include "error.h" #include "chebyshev.h" #include "cheb_eval.c" /*-*-*-*-*-*-*-*-*-*-*-* Private Section *-*-*-*-*-*-*-*-*-*-*-*/ /* Minimax rational approximation for [0,1), peak relative error = 2.04*GSL_DBL_EPSILON. Source: http://www.advanpix.com/?p=3812 */ static double k0_poly[8] = { 1.1593151565841244842077226e-01, 2.7898287891460317300886539e-01, 2.5248929932161220559969776e-02, 8.4603509072136578707676406e-04, 1.4914719243067801775856150e-05, 1.6271068931224552553548933e-07, 1.2082660336282566759313543e-09, 6.6117104672254184399933971e-12 }; static double i0_poly[7] = { 1.0000000000000000044974165e+00, 2.4999999999999822316775454e-01, 2.7777777777892149148858521e-02, 1.7361111083544590676709592e-03, 6.9444476047072424198677755e-05, 1.9288265756466775034067979e-06, 3.9908220583262192851839992e-08 }; /* Chebyshev expansion for [1,8], peak relative error = 1.28*GSL_DBL_EPSILON. Source: Pavel Holoborodko. */ static double ak0_data[24] = { -3.28737867094650101e-02, -4.49369057710236880e-02, +2.98149992004308095e-03, -3.03693649396187920e-04, +3.91085569307646836e-05, -5.86872422399215952e-06, +9.82873709937322009e-07, -1.78978645055651171e-07, +3.48332306845240957e-08, -7.15909210462546599e-09, +1.54019930048919494e-09, -3.44555485579194210e-10, +7.97356101783753023e-11, -1.90090968913069735e-11, +4.65295609304114621e-12, -1.16614287433470780e-12, +2.98554375218596891e-13, -7.79276979512292169e-14, +2.07027467168948402e-14, -5.58987860393825313e-15, +1.53202965950646914e-15, -4.25737536712188186e-16, +1.19840238501357389e-16, -3.41407346762502397e-17 }; static cheb_series ak0_cs = { ak0_data, 23, -1, 1, 10 }; /* Chebyshev expansion for [8,inf), peak relative error = 1.25*GSL_DBL_EPSILON. Source: SLATEC/dbsk0e.f */ static double ak02_data[14] = { -.1201869826307592240E-1, -.9174852691025695311E-2, +.1444550931775005821E-3, -.4013614175435709729E-5, +.1567831810852310673E-6, -.7770110438521737710E-8, +.4611182576179717883E-9, -.3158592997860565771E-10, +.2435018039365041128E-11, -.2074331387398347898E-12, +.1925787280589917085E-13, -.1927554805838956104E-14, +.2062198029197818278E-15, -.2341685117579242403E-16 }; static cheb_series ak02_cs = { ak02_data, 13, -1, 1, 8 }; /*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/ int gsl_sf_bessel_K0_scaled_e(const double x, gsl_sf_result * result) { /* CHECK_POINTER(result) */ if(x <= 0.0) { DOMAIN_ERROR(result); } else if(x < 1.0) { const double lx = log(x); const double ex = exp(x); const double x2 = x*x; result->val = ex * (gsl_poly_eval(k0_poly,8,x2)-lx*(1.0+0.25*x2*gsl_poly_eval(i0_poly,7,0.25*x2))); result->err = ex * (1.6+fabs(lx)*0.6) * GSL_DBL_EPSILON; result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_SUCCESS; } else if(x <= 8.0) { const double sx = sqrt(x); gsl_sf_result c; cheb_eval_e(&ak0_cs, (16.0/x-9.0)/7.0, &c); result->val = (1.203125 + c.val) / sx; /* 1.203125 = 77/64 */ result->err = c.err / sx; result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_SUCCESS; } else { const double sx = sqrt(x); gsl_sf_result c; cheb_eval_e(&ak02_cs, 16.0/x-1.0, &c); result->val = (1.25 + c.val) / sx; result->err = (c.err + GSL_DBL_EPSILON) / sx; result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_SUCCESS; } } int gsl_sf_bessel_K0_e(const double x, gsl_sf_result * result) { /* CHECK_POINTER(result) */ if(x <= 0.0) { DOMAIN_ERROR(result); } else if(x < 1.0) { const double lx = log(x); const double x2 = x*x; result->val = gsl_poly_eval(k0_poly,8,x2)-lx*(1.0+0.25*x2*gsl_poly_eval(i0_poly,7,0.25*x2)); result->err = (1.6+fabs(lx)*0.6) * GSL_DBL_EPSILON; result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_SUCCESS; } else { gsl_sf_result K0_scaled; int stat_K0 = gsl_sf_bessel_K0_scaled_e(x, &K0_scaled); int stat_e = gsl_sf_exp_mult_err_e(-x, GSL_DBL_EPSILON*fabs(x), K0_scaled.val, K0_scaled.err, result); return GSL_ERROR_SELECT_2(stat_e, stat_K0); } } /*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/ #include "eval.h" double gsl_sf_bessel_K0_scaled(const double x) { EVAL_RESULT(gsl_sf_bessel_K0_scaled_e(x, &result)); } double gsl_sf_bessel_K0(const double x) { EVAL_RESULT(gsl_sf_bessel_K0_e(x, &result)); }