mathieu_charv.c
来自「math library from gnu」· C语言 代码 · 共 850 行 · 第 1/2 页
C
850 行
/* specfunc/mathieu_charv.c * * Copyright (C) 2002 Lowell Johnson * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. *//* Author: L. Johnson */#include <config.h>#include <stdlib.h>#include <stdio.h>#include <math.h>#include <gsl/gsl_math.h>#include <gsl/gsl_eigen.h>#include <gsl/gsl_errno.h>#include <gsl/gsl_sf_mathieu.h>/* prototypes */static double solve_cubic(double c2, double c1, double c0);static double ceer(int order, double qq, double aa, int nterms){ double term, term1; int ii, n1; if (order == 0) term = 0.0; else { term = 2.0*qq*qq/aa; if (order != 2) { n1 = order/2 - 1; for (ii=0; ii<n1; ii++) term = qq*qq/(aa - 4.0*(ii+1)*(ii+1) - term); } } term += order*order; term1 = 0.0; for (ii=0; ii<nterms; ii++) term1 = qq*qq/ (aa - (order + 2.0*(nterms - ii))*(order + 2.0*(nterms - ii)) - term1); if (order == 0) term1 *= 2.0; return (term + term1 - aa);}static double ceor(int order, double qq, double aa, int nterms){ double term, term1; int ii, n1; term = qq; n1 = (int)((float)order/2.0 - 0.5); for (ii=0; ii<n1; ii++) term = qq*qq/(aa - (2.0*ii + 1.0)*(2.0*ii + 1.0) - term); term += order*order; term1 = 0.0; for (ii=0; ii<nterms; ii++) term1 = qq*qq/ (aa - (order + 2.0*(nterms - ii))*(order + 2.0*(nterms - ii)) - term1); return (term + term1 - aa);}static double seer(int order, double qq, double aa, int nterms){ double term, term1; int ii, n1; term = 0.0; n1 = order/2 - 1; for (ii=0; ii<n1; ii++) term = qq*qq/(aa - 4.0*(ii + 1)*(ii + 1) - term); term += order*order; term1 = 0.0; for (ii=0; ii<nterms; ii++) term1 = qq*qq/ (aa - (order + 2.0*(nterms - ii))*(order + 2.0*(nterms - ii)) - term1); return (term + term1 - aa);}static double seor(int order, double qq, double aa, int nterms){ double term, term1; int ii, n1; term = -1.0*qq; n1 = (int)((float)order/2.0 - 0.5); for (ii=0; ii<n1; ii++) term = qq*qq/(aa - (2.0*ii + 1.0)*(2.0*ii + 1.0) - term); term += order*order; term1 = 0.0; for (ii=0; ii<nterms; ii++) term1 = qq*qq/ (aa - (order + 2.0*(nterms - ii))*(order + 2.0*(nterms - ii)) - term1); return (term + term1 - aa);}/*---------------------------------------------------------------------------- * Asymptotic and approximation routines for the characteristic value. * * Adapted from F.A. Alhargan's paper, * "Algorithms for the Computation of All Mathieu Functions of Integer * Orders," ACM Transactions on Mathematical Software, Vol. 26, No. 3, * September 2000, pp. 390-407. *--------------------------------------------------------------------------*/static double asymptotic(int order, double qq){ double asymp; double nn, n2, n4, n6; double hh, ah, ah2, ah3, ah4, ah5; /* Set up temporary variables to simplify the readability. */ nn = 2*order + 1; n2 = nn*nn; n4 = n2*n2; n6 = n4*n2; hh = 2*sqrt(qq); ah = 16*hh; ah2 = ah*ah; ah3 = ah2*ah; ah4 = ah3*ah; ah5 = ah4*ah; /* Equation 38, p. 397 of Alhargan's paper. */ asymp = -2*qq + nn*hh - 0.125*(n2 + 1); asymp -= 0.25*nn*( n2 + 3)/ah; asymp -= 0.25* ( 5*n4 + 34*n2 + 9)/ah2; asymp -= 0.25*nn*( 33*n4 + 410*n2 + 405)/ah3; asymp -= ( 63*n6 + 1260*n4 + 2943*n2 + 486)/ah4; asymp -= nn*(527*n6 + 15617*n4 + 69001*n2 + 41607)/ah5; return asymp;}/* Solve the cubic x^3 + c2*x^2 + c1*x + c0 = 0 */static double solve_cubic(double c2, double c1, double c0){ double qq, rr, ww, ss, tt; qq = (3*c1 - c2*c2)/9; rr = (9*c2*c1 - 27*c0 - 2*c2*c2*c2)/54; ww = qq*qq*qq + rr*rr; if (ww >= 0) { double t1 = rr + sqrt(ww); ss = fabs(t1)/t1*pow(fabs(t1), 1/3.); t1 = rr - sqrt(ww); tt = fabs(t1)/t1*pow(fabs(t1), 1/3.); } else { double theta = acos(rr/sqrt(-qq*qq*qq)); ss = 2*sqrt(-qq)*cos((theta + 4*M_PI)/3.); tt = 0.0; } return (ss + tt - c2/3);}/* Compute an initial approximation for the characteristic value. */static double approx_c(int order, double qq){ double approx; double c0, c1, c2; if (order < 0) { GSL_ERROR_VAL("Undefined order for Mathieu function", GSL_EINVAL, 0.0); } switch (order) { case 0: if (qq <= 4) return (2 - sqrt(4 + 2*qq*qq)); /* Eqn. 31 */ else return asymptotic(order, qq); break; case 1: if (qq <= 4) return (5 + 0.5*(qq - sqrt(5*qq*qq - 16*qq + 64))); /* Eqn. 32 */ else return asymptotic(order, qq); break; case 2: if (qq <= 3) { c2 = -8.0; /* Eqn. 33 */ c1 = -48 - 3*qq*qq; c0 = 20*qq*qq; } else return asymptotic(order, qq); break; case 3: if (qq <= 6.25) { c2 = -qq - 8; /* Eqn. 34 */ c1 = 16*qq - 128 - 2*qq*qq; c0 = qq*qq*(qq + 8); } else return asymptotic(order, qq); break; default: if (order < 70) { if (1.7*order > 2*sqrt(qq)) { /* Eqn. 30 */ double n2 = (double)(order*order); double n22 = (double)((n2 - 1)*(n2 - 1)); double q2 = qq*qq; double q4 = q2*q2; approx = n2 + 0.5*q2/(n2 - 1); approx += (5*n2 + 7)*q4/(32*n22*(n2 - 1)*(n2 - 4)); approx += (9*n2*n2 + 58*n2 + 29)*q4*q2/ (64*n22*n22*(n2 - 1)*(n2 - 4)*(n2 - 9)); if (1.4*order < 2*sqrt(qq)) { approx += asymptotic(order, qq); approx *= 0.5; } } else approx = asymptotic(order, qq); return approx; } else return order*order; } /* Solve the cubic x^3 + c2*x^2 + c1*x + c0 = 0 */ approx = solve_cubic(c2, c1, c0); if ( approx < 0 && sqrt(qq) > 0.1*order ) return asymptotic(order-1, qq); else return (order*order + fabs(approx));} static double approx_s(int order, double qq){ double approx; double c0, c1, c2; if (order < 1) { GSL_ERROR_VAL("Undefined order for Mathieu function", GSL_EINVAL, 0.0); } switch (order) { case 1: if (qq <= 4) return (5 - 0.5*(qq + sqrt(5*qq*qq + 16*qq + 64))); /* Eqn. 35 */ else return asymptotic(order-1, qq); break; case 2: if (qq <= 5) return (10 - sqrt(36 + qq*qq)); /* Eqn. 36 */ else return asymptotic(order-1, qq); break; case 3: if (qq <= 6.25) { c2 = qq - 8; /* Eqn. 37 */ c1 = -128 - 16*qq - 2*qq*qq; c0 = qq*qq*(8 - qq); } else return asymptotic(order-1, qq); break; default: if (order < 70) { if (1.7*order > 2*sqrt(qq)) { /* Eqn. 30 */ double n2 = (double)(order*order); double n22 = (double)((n2 - 1)*(n2 - 1)); double q2 = qq*qq; double q4 = q2*q2; approx = n2 + 0.5*q2/(n2 - 1); approx += (5*n2 + 7)*q4/(32*n22*(n2 - 1)*(n2 - 4)); approx += (9*n2*n2 + 58*n2 + 29)*q4*q2/ (64*n22*n22*(n2 - 1)*(n2 - 4)*(n2 - 9)); if (1.4*order < 2*sqrt(qq)) { approx += asymptotic(order-1, qq); approx *= 0.5; } } else approx = asymptotic(order-1, qq); return approx; } else return order*order; } /* Solve the cubic x^3 + c2*x^2 + c1*x + c0 = 0 */ approx = solve_cubic(c2, c1, c0); if ( approx < 0 && sqrt(qq) > 0.1*order ) return asymptotic(order-1, qq); else return (order*order + fabs(approx));}int gsl_sf_mathieu_a(int order, double qq, gsl_sf_result *result){ int even_odd, nterms = 50, ii, counter = 0, maxcount = 200; double a1, a2, fa, fa1, dela, aa_orig, da = 0.025, aa; even_odd = 0; if (order % 2 != 0) even_odd = 1; /* If the argument is 0, then the coefficient is simply the square of the order. */ if (qq == 0) { result->val = order*order; result->err = 0.0; return GSL_SUCCESS; } /* Use symmetry characteristics of the functions to handle cases with negative order and/or argument q. See Abramowitz & Stegun, 20.8.3. */ if (order < 0) order *= -1; if (qq < 0.0) { if (even_odd == 0) return gsl_sf_mathieu_a(order, -qq, result); else return gsl_sf_mathieu_b(order, -qq, result); } /* Compute an initial approximation for the characteristic value. */ aa = approx_c(order, qq); /* Save the original approximation for later comparison. */ aa_orig = aa; /* Loop as long as the final value is not near the approximate value (with a max limit to avoid potential infinite loop). */ while (counter < maxcount) { a1 = aa + 0.001; ii = 0; if (even_odd == 0) fa1 = ceer(order, qq, a1, nterms); else fa1 = ceor(order, qq, a1, nterms); for (;;) { if (even_odd == 0) fa = ceer(order, qq, aa, nterms); else fa = ceor(order, qq, aa, nterms); a2 = a1;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?