|
Packit |
67cb25 |
/* specfunc/mathieu_coeff.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 2002 Lowell Johnson
|
|
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Author: L. Johnson */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include <config.h>
|
|
Packit |
67cb25 |
#include <stdlib.h>
|
|
Packit |
67cb25 |
#include <math.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_sf_mathieu.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*****************************************************************************
|
|
Packit |
67cb25 |
* backward_recurse
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Purpose:
|
|
Packit |
67cb25 |
****************************************************************************/
|
|
Packit |
67cb25 |
static void backward_recurse_c(double aa, double qq, double xx, double *ff,
|
|
Packit |
67cb25 |
double *gx, int even_odd, int ni)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int ii, nn;
|
|
Packit |
67cb25 |
double g1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
g1 = *gx;
|
|
Packit |
67cb25 |
ff[ni] = xx;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (even_odd == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (ii=0; ii
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
nn = GSL_SF_MATHIEU_COEFF - ii - 1;
|
|
Packit |
67cb25 |
ff[ni-ii-1] = -1.0/((4*nn*nn - aa)/qq + ff[ni-ii]);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
if (ni == GSL_SF_MATHIEU_COEFF - 1)
|
|
Packit |
67cb25 |
ff[0] *= 2.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (ii=0; ii
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
nn = GSL_SF_MATHIEU_COEFF - ii - 1;
|
|
Packit |
67cb25 |
ff[ni-ii-1] = -1.0/(((2*nn + 1)*(2*nn + 1) - aa)/qq + ff[ni-ii]);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*gx = ff[0] - g1;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void backward_recurse_s(double aa, double qq, double xx, double *ff,
|
|
Packit |
67cb25 |
double *gx, int even_odd, int ni)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int ii, nn;
|
|
Packit |
67cb25 |
double g1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
g1 = *gx;
|
|
Packit |
67cb25 |
ff[ni] = xx;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (even_odd == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (ii=0; ii
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
nn = GSL_SF_MATHIEU_COEFF - ii - 1;
|
|
Packit |
67cb25 |
ff[ni-ii-1] = -1.0/((4*(nn + 1)*(nn + 1) - aa)/qq + ff[ni-ii]);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (ii=0; ii
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
nn = GSL_SF_MATHIEU_COEFF - ii - 1;
|
|
Packit |
67cb25 |
ff[ni-ii-1] = -1.0/(((2*nn + 1)*(2*nn + 1) - aa)/qq + ff[ni-ii]);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*gx = ff[0] - g1;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int gsl_sf_mathieu_a_coeff(int order, double qq, double aa, double coeff[])
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int ni, nn, ii, even_odd;
|
|
Packit |
67cb25 |
double eps, g1, g2, x1, x2, e1, e2, de, xh, sum, ratio,
|
|
Packit |
67cb25 |
ff[GSL_SF_MATHIEU_COEFF];
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
eps = 1e-14;
|
|
Packit |
67cb25 |
coeff[0] = 1.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
even_odd = 0;
|
|
Packit |
67cb25 |
if (order % 2 != 0)
|
|
Packit |
67cb25 |
even_odd = 1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* If the coefficient array is not large enough to hold all necessary
|
|
Packit |
67cb25 |
coefficients, error out. */
|
|
Packit |
67cb25 |
if (order > GSL_SF_MATHIEU_COEFF)
|
|
Packit |
67cb25 |
return GSL_FAILURE;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Handle the trivial case where q = 0. */
|
|
Packit |
67cb25 |
if (qq == 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (ii=0; ii
|
|
Packit |
67cb25 |
coeff[ii] = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
coeff[order/2] = 1.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (order < 5)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
nn = 0;
|
|
Packit |
67cb25 |
sum = 0.0;
|
|
Packit |
67cb25 |
if (even_odd == 0)
|
|
Packit |
67cb25 |
ratio = aa/qq;
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
ratio = (aa - 1 - qq)/qq;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (even_odd == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
coeff[1] = aa/qq;
|
|
Packit |
67cb25 |
coeff[2] = (aa - 4)/qq*coeff[1] - 2;
|
|
Packit |
67cb25 |
sum = coeff[0] + coeff[1] + coeff[2];
|
|
Packit |
67cb25 |
for (ii=3; ii
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
coeff[ii] = (aa - 4*(ii - 1)*(ii - 1))/qq*coeff[ii-1] -
|
|
Packit |
67cb25 |
coeff[ii-2];
|
|
Packit |
67cb25 |
sum += coeff[ii];
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
coeff[1] = (aa - 1)/qq - 1;
|
|
Packit |
67cb25 |
sum = coeff[0] + coeff[1];
|
|
Packit |
67cb25 |
for (ii=2; ii
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
coeff[ii] = (aa - (2*ii - 1)*(2*ii - 1))/qq*coeff[ii-1] -
|
|
Packit |
67cb25 |
coeff[ii-2];
|
|
Packit |
67cb25 |
sum += coeff[ii];
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
nn = ii - 1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
ratio = coeff[nn]/coeff[nn-1];
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
ni = GSL_SF_MATHIEU_COEFF - nn - 1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Compute first two points to start root-finding. */
|
|
Packit |
67cb25 |
if (even_odd == 0)
|
|
Packit |
67cb25 |
x1 = -qq/(4.0*GSL_SF_MATHIEU_COEFF*GSL_SF_MATHIEU_COEFF);
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
x1 = -qq/((2.0*GSL_SF_MATHIEU_COEFF + 1.0)*(2.0*GSL_SF_MATHIEU_COEFF + 1.0));
|
|
Packit |
67cb25 |
g1 = ratio;
|
|
Packit |
67cb25 |
backward_recurse_c(aa, qq, x1, ff, &g1, even_odd, ni);
|
|
Packit |
67cb25 |
x2 = g1;
|
|
Packit |
67cb25 |
g2 = ratio;
|
|
Packit |
67cb25 |
backward_recurse_c(aa, qq, x2, ff, &g2, even_odd, ni);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Find the root. */
|
|
Packit |
67cb25 |
while (1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* Compute the relative error. */
|
|
Packit |
67cb25 |
e1 = g1 - x1;
|
|
Packit |
67cb25 |
e2 = g2 - x2;
|
|
Packit |
67cb25 |
de = e1 - e2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* If we are close enough to the root, break... */
|
|
Packit |
67cb25 |
if (fabs(de) < eps)
|
|
Packit |
67cb25 |
break;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Otherwise, determine the next guess and try again. */
|
|
Packit |
67cb25 |
xh = (e1*x2 - e2*x1)/de;
|
|
Packit |
67cb25 |
x1 = x2;
|
|
Packit |
67cb25 |
g1 = g2;
|
|
Packit |
67cb25 |
x2 = xh;
|
|
Packit |
67cb25 |
g2 = ratio;
|
|
Packit |
67cb25 |
backward_recurse_c(aa, qq, x2, ff, &g2, even_odd, ni);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Compute the rest of the coefficients. */
|
|
Packit |
67cb25 |
sum += coeff[nn];
|
|
Packit |
67cb25 |
for (ii=nn+1; ii
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
coeff[ii] = ff[ii-nn-1]*coeff[ii-1];
|
|
Packit |
67cb25 |
sum += coeff[ii];
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* If the coefficients are getting really small, set the remainder
|
|
Packit |
67cb25 |
to zero. */
|
|
Packit |
67cb25 |
if (fabs(coeff[ii]) < 1e-20)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (; ii
|
|
Packit |
67cb25 |
coeff[ii++] = 0.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Normalize the coefficients. */
|
|
Packit |
67cb25 |
for (ii=0; ii
|
|
Packit |
67cb25 |
coeff[ii] /= sum;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int gsl_sf_mathieu_b_coeff(int order, double qq, double aa, double coeff[])
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
int ni, nn, ii, even_odd;
|
|
Packit |
67cb25 |
double eps, g1, g2, x1, x2, e1, e2, de, xh, sum, ratio,
|
|
Packit |
67cb25 |
ff[GSL_SF_MATHIEU_COEFF];
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
eps = 1e-10;
|
|
Packit |
67cb25 |
coeff[0] = 1.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
even_odd = 0;
|
|
Packit |
67cb25 |
if (order % 2 != 0)
|
|
Packit |
67cb25 |
even_odd = 1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* If the coefficient array is not large enough to hold all necessary
|
|
Packit |
67cb25 |
coefficients, error out. */
|
|
Packit |
67cb25 |
if (order > GSL_SF_MATHIEU_COEFF)
|
|
Packit |
67cb25 |
return GSL_FAILURE;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Handle the trivial case where q = 0. */
|
|
Packit |
67cb25 |
if (qq == 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (ii=0; ii
|
|
Packit |
67cb25 |
coeff[ii] = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
coeff[(order-1)/2] = 1.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (order < 5)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
nn = 0;
|
|
Packit |
67cb25 |
sum = 0.0;
|
|
Packit |
67cb25 |
if (even_odd == 0)
|
|
Packit |
67cb25 |
ratio = (aa - 4)/qq;
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
ratio = (aa - 1 - qq)/qq;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (even_odd == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
coeff[1] = (aa - 4)/qq;
|
|
Packit |
67cb25 |
sum = 2*coeff[0] + 4*coeff[1];
|
|
Packit |
67cb25 |
for (ii=2; ii
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
coeff[ii] = (aa - 4*ii*ii)/qq*coeff[ii-1] - coeff[ii-2];
|
|
Packit |
67cb25 |
sum += 2*(ii + 1)*coeff[ii];
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
coeff[1] = (aa - 1)/qq + 1;
|
|
Packit |
67cb25 |
sum = coeff[0] + 3*coeff[1];
|
|
Packit |
67cb25 |
for (ii=2; ii
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
coeff[ii] = (aa - (2*ii - 1)*(2*ii - 1))/qq*coeff[ii-1] -
|
|
Packit |
67cb25 |
coeff[ii-2];
|
|
Packit |
67cb25 |
sum += (2*(ii + 1) - 1)*coeff[ii];
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
nn = ii - 1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
ratio = coeff[nn]/coeff[nn-1];
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
ni = GSL_SF_MATHIEU_COEFF - nn - 1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Compute first two points to start root-finding. */
|
|
Packit |
67cb25 |
if (even_odd == 0)
|
|
Packit |
67cb25 |
x1 = -qq/(4.0*(GSL_SF_MATHIEU_COEFF + 1.0)*(GSL_SF_MATHIEU_COEFF + 1.0));
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
x1 = -qq/((2.0*GSL_SF_MATHIEU_COEFF + 1.0)*(2.0*GSL_SF_MATHIEU_COEFF + 1.0));
|
|
Packit |
67cb25 |
g1 = ratio;
|
|
Packit |
67cb25 |
backward_recurse_s(aa, qq, x1, ff, &g1, even_odd, ni);
|
|
Packit |
67cb25 |
x2 = g1;
|
|
Packit |
67cb25 |
g2 = ratio;
|
|
Packit |
67cb25 |
backward_recurse_s(aa, qq, x2, ff, &g2, even_odd, ni);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Find the root. */
|
|
Packit |
67cb25 |
while (1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* Compute the relative error. */
|
|
Packit |
67cb25 |
e1 = g1 - x1;
|
|
Packit |
67cb25 |
e2 = g2 - x2;
|
|
Packit |
67cb25 |
de = e1 - e2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* If we are close enough to the root, break... */
|
|
Packit |
67cb25 |
if (fabs(de) < eps)
|
|
Packit |
67cb25 |
break;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Otherwise, determine the next guess and try again. */
|
|
Packit |
67cb25 |
xh = (e1*x2 - e2*x1)/de;
|
|
Packit |
67cb25 |
x1 = x2;
|
|
Packit |
67cb25 |
g1 = g2;
|
|
Packit |
67cb25 |
x2 = xh;
|
|
Packit |
67cb25 |
g2 = ratio;
|
|
Packit |
67cb25 |
backward_recurse_s(aa, qq, x2, ff, &g2, even_odd, ni);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Compute the rest of the coefficients. */
|
|
Packit |
67cb25 |
sum += 2*(nn + 1)*coeff[nn];
|
|
Packit |
67cb25 |
for (ii=nn+1; ii
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
coeff[ii] = ff[ii-nn-1]*coeff[ii-1];
|
|
Packit |
67cb25 |
sum += 2*(ii + 1)*coeff[ii];
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* If the coefficients are getting really small, set the remainder
|
|
Packit |
67cb25 |
to zero. */
|
|
Packit |
67cb25 |
if (fabs(coeff[ii]) < 1e-20)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (; ii
|
|
Packit |
67cb25 |
coeff[ii++] = 0.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Normalize the coefficients. */
|
|
Packit |
67cb25 |
for (ii=0; ii
|
|
Packit |
67cb25 |
coeff[ii] /= sum;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|