⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 legendre_con.c

📁 开放gsl矩阵运算
💻 C
📖 第 1 页 / 共 3 页
字号:
/* specfunc/legendre_con.c *  * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman *  * 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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA. *//* Author:  G. Jungman */#include <config.h>#include <gsl/gsl_math.h>#include <gsl/gsl_errno.h>#include <gsl/gsl_poly.h>#include "gsl_sf_exp.h"#include "gsl_sf_trig.h"#include "gsl_sf_gamma.h"#include "gsl_sf_ellint.h"#include "gsl_sf_pow_int.h"#include "gsl_sf_bessel.h"#include "gsl_sf_hyperg.h"#include "gsl_sf_legendre.h"#include "error.h"#include "legendre.h"#define Root_2OverPi_  0.797884560802865355879892#define locEPS         (1000.0*GSL_DBL_EPSILON)/*-*-*-*-*-*-*-*-*-*-*-* Private Section *-*-*-*-*-*-*-*-*-*-*-*/#define RECURSE_LARGE  (1.0e-5*GSL_DBL_MAX)#define RECURSE_SMALL  (1.0e+5*GSL_DBL_MIN)/* Continued fraction for f_{ell+1}/f_ell * f_ell := P^{-mu-ell}_{-1/2 + I tau}(x),  x < 1.0 * * Uses standard CF method from Temme's book. */staticintconicalP_negmu_xlt1_CF1(const double mu, const int ell, const double tau,                        const double x, gsl_sf_result * result){  const double RECUR_BIG = GSL_SQRT_DBL_MAX;  const int maxiter = 5000;  int n = 1;  double xi = x/(sqrt(1.0-x)*sqrt(1.0+x));  double Anm2 = 1.0;  double Bnm2 = 0.0;  double Anm1 = 0.0;  double Bnm1 = 1.0;  double a1 = 1.0;  double b1 = 2.0*(mu + ell + 1.0) * xi;  double An = b1*Anm1 + a1*Anm2;  double Bn = b1*Bnm1 + a1*Bnm2;  double an, bn;  double fn = An/Bn;  while(n < maxiter) {    double old_fn;    double del;    n++;    Anm2 = Anm1;    Bnm2 = Bnm1;    Anm1 = An;    Bnm1 = Bn;    an = tau*tau + (mu - 0.5 + ell + n)*(mu - 0.5 + ell + n);    bn = 2.0*(ell + mu + n) * xi;    An = bn*Anm1 + an*Anm2;    Bn = bn*Bnm1 + an*Bnm2;    if(fabs(An) > RECUR_BIG || fabs(Bn) > RECUR_BIG) {      An /= RECUR_BIG;      Bn /= RECUR_BIG;      Anm1 /= RECUR_BIG;      Bnm1 /= RECUR_BIG;      Anm2 /= RECUR_BIG;      Bnm2 /= RECUR_BIG;    }    old_fn = fn;    fn = An/Bn;    del = old_fn/fn;        if(fabs(del - 1.0) < 2.0*GSL_DBL_EPSILON) break;  }  result->val = fn;  result->err = 4.0 * GSL_DBL_EPSILON * (sqrt(n) + 1.0) * fabs(fn);  if(n >= maxiter)    GSL_ERROR ("error", GSL_EMAXITER);  else    return GSL_SUCCESS;}/* Continued fraction for f_{ell+1}/f_ell * f_ell := P^{-mu-ell}_{-1/2 + I tau}(x),  x >= 1.0 * * Uses Gautschi (Euler) equivalent series. */staticintconicalP_negmu_xgt1_CF1(const double mu, const int ell, const double tau,                        const double x, gsl_sf_result * result){   const int maxk = 20000;  const double gamma = 1.0-1.0/(x*x);  const double pre = sqrt(x-1.0)*sqrt(x+1.0) / (x*(2.0*(ell+mu+1.0)));  double tk   = 1.0;  double sum  = 1.0;  double rhok = 0.0;  int k;   for(k=1; k<maxk; k++) {    double tlk = 2.0*(ell + mu + k);    double l1k = (ell + mu - 0.5 + 1.0 + k);    double ak = -(tau*tau + l1k*l1k)/(tlk*(tlk+2.0)) * gamma;    rhok = -ak*(1.0 + rhok)/(1.0 + ak*(1.0 + rhok));    tk  *= rhok;    sum += tk;    if(fabs(tk/sum) < GSL_DBL_EPSILON) break;  }  result->val  = pre * sum;  result->err  = fabs(pre * tk);  result->err += 2.0 * GSL_DBL_EPSILON * (sqrt(k) + 1.0) * fabs(pre*sum);  if(k >= maxk)    GSL_ERROR ("error", GSL_EMAXITER);  else    return GSL_SUCCESS;}/* Implementation of large negative mu asymptotic * [Dunster, Proc. Roy. Soc. Edinburgh 119A, 311 (1991), p. 326] */inlinestatic double olver_U1(double beta2, double p){  return (p-1.0)/(24.0*(1.0+beta2)) * (3.0 + beta2*(2.0 + 5.0*p*(1.0+p)));}inlinestatic double olver_U2(double beta2, double p){  double beta4 = beta2*beta2;  double p2    = p*p;  double poly1 =  4.0*beta4 + 84.0*beta2 - 63.0;  double poly2 = 16.0*beta4 + 90.0*beta2 - 81.0;  double poly3 = beta2*p2*(97.0*beta2 - 432.0 + 77.0*p*(beta2-6.0) - 385.0*beta2*p2*(1.0 + p));  return (1.0-p)/(1152.0*(1.0+beta2)) * (poly1 + poly2 + poly3);}static const double U3c1[] = {   -1307.0,   -1647.0,    3375.0,    3675.0 };static const double U3c2[] = {   29366.0,   35835.0, -252360.0, -272630.0,                                276810.0,  290499.0 };static const double U3c3[] = {  -29748.0,   -8840.0, 1725295.0, 1767025.0,                              -7313470.0, -754778.0, 6309875.0, 6480045.0 };static const double U3c4[] = {    2696.0,    -16740.0,   -524250.0,  -183975.0,                              14670540.0,  14172939.0, -48206730.0, -48461985.0,			      36756720.0,  37182145.0 };static const double U3c5[] = {       9136.0,      22480.0,     12760.0,                                  -252480.0,   -4662165.0,   -1705341.0,				 92370135.0,   86244015.0, -263678415.0,			       -260275015.0, 185910725.0,  185910725.0 };#if 0static double olver_U3(double beta2, double p){  double beta4 = beta2*beta2;  double beta6 = beta4*beta2;  double opb2s = (1.0+beta2)*(1.0+beta2);  double den   = 39813120.0 * opb2s*opb2s;  double poly1 = gsl_poly_eval(U3c1, 4, p);  double poly2 = gsl_poly_eval(U3c2, 6, p);  double poly3 = gsl_poly_eval(U3c3, 8, p);  double poly4 = gsl_poly_eval(U3c4, 10, p);  double poly5 = gsl_poly_eval(U3c5, 12, p);    return (p-1.0)*(     1215.0*poly1 + 324.0*beta2*poly2                 + 54.0*beta4*poly3 +  12.0*beta6*poly4		 + beta4*beta4*poly5		 ) / den;}#endif /* 0 *//* Large negative mu asymptotic * P^{-mu}_{-1/2 + I tau}, mu -> Inf * |x| < 1 * * [Dunster, Proc. Roy. Soc. Edinburgh 119A, 311 (1991), p. 326] */intgsl_sf_conicalP_xlt1_large_neg_mu_e(double mu, double tau, double x,                                       gsl_sf_result * result, double * ln_multiplier){  double beta  = tau/mu;  double beta2 = beta*beta;  double S     = beta * acos((1.0-beta2)/(1.0+beta2));  double p     = x/sqrt(beta2*(1.0-x*x) + 1.0);  gsl_sf_result lg_mup1;  int lg_stat = gsl_sf_lngamma_e(mu+1.0, &lg_mup1);  double ln_pre_1 =  0.5*mu*(S - log(1.0+beta2) + log((1.0-p)/(1.0+p))) - lg_mup1.val;  double ln_pre_2 = -0.25 * log(1.0 + beta2*(1.0-x));  double ln_pre_3 = -tau * atan(p*beta);  double ln_pre = ln_pre_1 + ln_pre_2 + ln_pre_3;  double sum   = 1.0 - olver_U1(beta2, p)/mu + olver_U2(beta2, p)/(mu*mu);  if(sum == 0.0) {    result->val = 0.0;    result->err = 0.0;    *ln_multiplier = 0.0;    return GSL_SUCCESS;  }  else {    int stat_e = gsl_sf_exp_mult_e(ln_pre, sum, result);    if(stat_e != GSL_SUCCESS) {      result->val = sum;      result->err = 2.0 * GSL_DBL_EPSILON * fabs(sum);      *ln_multiplier = ln_pre;    }    else {      *ln_multiplier = 0.0;    }    return lg_stat;  }}/* Implementation of large tau asymptotic * * A_n^{-mu}, B_n^{-mu}  [Olver, p.465, 469] */inlinestatic double olver_B0_xi(double mu, double xi){  return (1.0 - 4.0*mu*mu)/(8.0*xi) * (1.0/tanh(xi) - 1.0/xi);}static double olver_A1_xi(double mu, double xi, double x){  double B = olver_B0_xi(mu, xi);  double psi;  if(fabs(x - 1.0) < GSL_ROOT4_DBL_EPSILON) {    double y = x - 1.0;    double s = -1.0/3.0 + y*(2.0/15.0 - y *(61.0/945.0 - 452.0/14175.0*y));    psi = (4.0*mu*mu - 1.0)/16.0 * s;  }  else {    psi = (4.0*mu*mu - 1.0)/16.0 * (1.0/(x*x-1.0) - 1.0/(xi*xi));  }  return 0.5*xi*xi*B*B + (mu+0.5)*B - psi + mu/6.0*(0.25 - mu*mu);}inlinestatic double olver_B0_th(double mu, double theta){  return -(1.0 - 4.0*mu*mu)/(8.0*theta) * (1.0/tan(theta) - 1.0/theta);}static double olver_A1_th(double mu, double theta, double x){  double B = olver_B0_th(mu, theta);  double psi;  if(fabs(x - 1.0) < GSL_ROOT4_DBL_EPSILON) {    double y = 1.0 - x;    double s = -1.0/3.0 + y*(2.0/15.0 - y *(61.0/945.0 - 452.0/14175.0*y));    psi = (4.0*mu*mu - 1.0)/16.0 * s;  }  else {    psi = (4.0*mu*mu - 1.0)/16.0 * (1.0/(x*x-1.0) + 1.0/(theta*theta));  }  return -0.5*theta*theta*B*B + (mu+0.5)*B - psi + mu/6.0*(0.25 - mu*mu);}/* Large tau uniform asymptotics * P^{-mu}_{-1/2 + I tau} * 1 < x * tau -> Inf  * [Olver, p. 469] */intgsl_sf_conicalP_xgt1_neg_mu_largetau_e(const double mu, const double tau,                                          const double x, double acosh_x,                                          gsl_sf_result * result, double * ln_multiplier){  double xi = acosh_x;  double ln_xi_pre;  double ln_pre;  double sumA, sumB, sum;  double arg;  gsl_sf_result J_mup1;  gsl_sf_result J_mu;  double J_mum1;  if(xi < GSL_ROOT4_DBL_EPSILON) {    ln_xi_pre = -xi*xi/6.0;           /* log(1.0 - xi*xi/6.0) */  }  else {    gsl_sf_result lnshxi;    gsl_sf_lnsinh_e(xi, &lnshxi);    ln_xi_pre = log(xi) - lnshxi.val;     /* log(xi/sinh(xi) */  }  ln_pre = 0.5*ln_xi_pre - mu*log(tau);  arg = tau*xi;  gsl_sf_bessel_Jnu_e(mu + 1.0,   arg, &J_mup1);  gsl_sf_bessel_Jnu_e(mu,         arg, &J_mu);  J_mum1 = -J_mup1.val + 2.0*mu/arg*J_mu.val;      /* careful of mu < 1 */  sumA = 1.0 - olver_A1_xi(-mu, xi, x)/(tau*tau);  sumB = olver_B0_xi(-mu, xi);  sum  = J_mu.val * sumA - xi/tau * J_mum1 * sumB;  if(sum == 0.0) {    result->val = 0.0;    result->err = 0.0;    *ln_multiplier = 0.0;    return GSL_SUCCESS;  }  else {    int stat_e = gsl_sf_exp_mult_e(ln_pre, sum, result);    if(stat_e != GSL_SUCCESS) {      result->val = sum;      result->err = 2.0 * GSL_DBL_EPSILON * fabs(sum);      *ln_multiplier = ln_pre;    }    else {      *ln_multiplier = 0.0;    }    return GSL_SUCCESS;  }}/* Large tau uniform asymptotics * P^{-mu}_{-1/2 + I tau} * -1 < x < 1 * tau -> Inf  * [Olver, p. 473] */intgsl_sf_conicalP_xlt1_neg_mu_largetau_e(const double mu, const double tau,                                          const double x, const double acos_x,                                          gsl_sf_result * result, double * ln_multiplier){  double theta = acos_x;  double ln_th_pre;  double ln_pre;  double sumA, sumB, sum, sumerr;  double arg;  gsl_sf_result I_mup1, I_mu;  double I_mum1;  if(theta < GSL_ROOT4_DBL_EPSILON) {    ln_th_pre = theta*theta/6.0;   /* log(1.0 + theta*theta/6.0) */  }  else {    ln_th_pre = log(theta/sin(theta));  }  ln_pre = 0.5 * ln_th_pre - mu * log(tau);  arg = tau*theta;  gsl_sf_bessel_Inu_e(mu + 1.0,   arg, &I_mup1);  gsl_sf_bessel_Inu_e(mu,         arg, &I_mu);  I_mum1 = I_mup1.val + 2.0*mu/arg * I_mu.val; /* careful of mu < 1 */  sumA = 1.0 - olver_A1_th(-mu, theta, x)/(tau*tau);  sumB = olver_B0_th(-mu, theta);  sum  = I_mu.val * sumA - theta/tau * I_mum1 * sumB;  sumerr  = fabs(I_mu.err * sumA);  sumerr += fabs(I_mup1.err * theta/tau * sumB);  sumerr += fabs(I_mu.err   * theta/tau * sumB * 2.0 * mu/arg);  if(sum == 0.0) {    result->val = 0.0;    result->err = 0.0;    *ln_multiplier = 0.0;    return GSL_SUCCESS;  }  else {    int stat_e = gsl_sf_exp_mult_e(ln_pre, sum, result);    if(stat_e != GSL_SUCCESS) {      result->val  = sum;      result->err  = sumerr;      result->err += GSL_DBL_EPSILON * fabs(sum);      *ln_multiplier = ln_pre;    }    else {      *ln_multiplier = 0.0;    }    return GSL_SUCCESS;  }}/* Hypergeometric function which appears in the * large x expansion below: * *   2F1(1/4 - mu/2 - I tau/2, 3/4 - mu/2 - I tau/2, 1 - I tau, y) * * Note that for the usage below y = 1/x^2; */staticintconicalP_hyperg_large_x(const double mu, const double tau, const double y,                        double * reF, double * imF){  const int kmax = 1000;  const double re_a = 0.25 - 0.5*mu;  const double re_b = 0.75 - 0.5*mu;  const double re_c = 1.0;  const double im_a = -0.5*tau;  const double im_b = -0.5*tau;  const double im_c = -tau;  double re_sum = 1.0;  double im_sum = 0.0;  double re_term = 1.0;  double im_term = 0.0;  int k;  for(k=1; k<=kmax; k++) {    double re_ak = re_a + k - 1.0;    double re_bk = re_b + k - 1.0;    double re_ck = re_c + k - 1.0;    double im_ak = im_a;    double im_bk = im_b;    double im_ck = im_c;    double den = re_ck*re_ck + im_ck*im_ck;    double re_multiplier = ((re_ak*re_bk - im_ak*im_bk)*re_ck + im_ck*(im_ak*re_bk + re_ak*im_bk)) / den;    double im_multiplier = ((im_ak*re_bk + re_ak*im_bk)*re_ck - im_ck*(re_ak*re_bk - im_ak*im_bk)) / den;    double re_tmp = re_multiplier*re_term - im_multiplier*im_term;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -