/* Author: G. Jungman * RCS: $Id: chebyshev.c,v 1.21 1999/05/07 23:36:22 jungman Exp $ */ #include #include #include #include #include "gsl_sf_chebyshev.h" /*-*-*-*-*-*-*-*-*-*-*-* Allocators *-*-*-*-*-*-*-*-*-*-*-*/ gsl_sf_cheb_series * gsl_sf_cheb_new(double (*func)(double), const double a, const double b, const int order) { int status; if(order < 0) { GSL_ERROR_RETURN("gsl_sf_cheb_new: order < 0", GSL_EDOM, 0); } else if(a >= b) { GSL_ERROR_RETURN("gsl_sf_cheb_new: null interval, a>=b", GSL_EDOM, 0); } #if 0 else if(fabs(b-a) < 1.0e+6 * GSL_DBL_EPSILON) { /* FIXME: arbitrary nonsense */ GSL_ERROR_RETURN("gsl_sf_cheb_new: interval close to null", GSL_EFAILED, 0); } #endif else { gsl_sf_cheb_series * cs = (gsl_sf_cheb_series *) malloc(sizeof(gsl_sf_cheb_series)); if(cs == 0) { GSL_ERROR_RETURN("gsl_sf_cheb_new: out of memory", GSL_ENOMEM, 0); } cs->cp = (double *)0; cs->ci = (double *)0; cs->order = order; cs->order_sp = order; cs->a = a; cs->b = b; cs->c = (double *) malloc((order+1) * sizeof(double)); if(cs->c == 0) { GSL_ERROR_RETURN("gsl_sf_cheb_new: out of memory", GSL_ENOMEM, 0); } status = gsl_sf_cheb_calc_impl(cs, func); if(status != GSL_SUCCESS) { free(cs); GSL_ERROR_RETURN("gsl_sf_cheb_new: calc failed", status, 0); } else { return cs; } } } /*-*-*-*-*-*-*-*-*-*-*-* (semi)Private Implementations *-*-*-*-*-*-*-*-*-*-*-*/ int gsl_sf_cheb_calc_impl(gsl_sf_cheb_series * cs, double (*func)(double)) { if(cs == 0) { return GSL_EFAULT; } else { int k, j; double bma = 0.5 * (cs->b - cs->a); double bpa = 0.5 * (cs->b + cs->a); double fac = 2.0/(cs->order +1.0); double * f = (double *) malloc((cs->order+1) * sizeof(double)); if(f == 0) { return GSL_ENOMEM; } for(k = 0; k<=cs->order; k++) { double y = cos(M_PI * (k+0.5)/(cs->order+1)); f[k] = func(y*bma + bpa); } for(j = 0; j<=cs->order; j++) { double sum = 0.0; for(k = 0; k<=cs->order; k++) sum += f[k]*cos(M_PI * j*(k+0.5)/(cs->order+1)); cs->c[j] = fac * sum; } free(f); return GSL_SUCCESS; } } int gsl_sf_cheb_calc_deriv_impl(gsl_sf_cheb_series * cs) { const int n = cs->order + 1; const double con = 2.0 / (cs->b - cs->a); int j; if(cs->cp != 0) free(cs->cp); cs->cp = (double *) malloc(n * sizeof(double)); if(cs->cp == 0) return GSL_ENOMEM; cs->cp[n-1] = 0.0; if(n > 1) { cs->cp[n-2] = 2*(n-1) * cs->c[n-1]; for(j = n-3; j>=0; j--) cs->cp[j] = cs->cp[j+2] + 2*(j+1) * cs->c[j+1]; for(j = 0 ; jcp[j] *= con; } return GSL_SUCCESS; } int gsl_sf_cheb_calc_integ_impl(gsl_sf_cheb_series * cs) { const int n = cs->order + 1; const double con = 0.25 * (cs->b - cs->a); if(cs->ci != 0) free(cs->ci); cs->ci = (double *) malloc(n * sizeof(double)); if(cs->ci == 0) return GSL_ENOMEM; if(n == 1) { cs->ci[0] = 0.; } else if(n == 2) { cs->ci[1] = con * cs->c[0]; cs->ci[0] = 2.0 * cs->ci[1]; } else { double sum = 0.0; double fac = 1.0; int j; for(j=1; j<=n-2; j++) { cs->ci[j] = con * (cs->c[j-1] - cs->c[j+1])/j; sum += fac * cs->ci[j]; fac = -fac; } cs->ci[n-1] = con * cs->c[n-2]/(n-1); sum += fac * cs->ci[n-1]; cs->ci[0] = 2.0 * sum; } return GSL_SUCCESS; } int gsl_sf_cheb_eval_n_impl(const gsl_sf_cheb_series * cs, const int n, const double x, gsl_sf_result * result) { int j; double d = 0.0; double dd = 0.0; double y = (2.*x - cs->a - cs->b) / (cs->b - cs->a); double y2 = 2.0 * y; int eval_order = GSL_MAX_INT(0, GSL_MIN_INT(n, cs->order)); for(j = eval_order; j>=1; j--) { double temp = d; d = y2*d - dd + cs->c[j]; dd = temp; } if(result == 0) { return GSL_EFAULT; } else { result->val = y*d - dd + 0.5 * cs->c[0]; result->err = fabs(cs->c[eval_order]); return GSL_SUCCESS; } } int gsl_sf_cheb_eval_impl(const gsl_sf_cheb_series * cs, const double x, gsl_sf_result * result) { int j; double d = 0.0; double dd = 0.0; double y = (2.0*x - cs->a - cs->b) / (cs->b - cs->a); double y2 = 2.0 * y; for(j = cs->order; j>=1; j--) { double temp = d; d = y2*d - dd + cs->c[j]; dd = temp; } if(result == 0) { return GSL_EFAULT; } else { result->val = y*d - dd + 0.5 * cs->c[0]; result->err = GSL_DBL_EPSILON * fabs(result->val) + fabs(cs->c[cs->order]); return GSL_SUCCESS; } } int gsl_sf_cheb_eval_mode_impl(const gsl_sf_cheb_series * cs, const double x, gsl_mode_t mode, gsl_sf_result * result) { int j; double d = 0.0; double dd = 0.0; double y = (2.*x - cs->a - cs->b) / (cs->b - cs->a); double y2 = 2.0 * y; int eval_order; if(GSL_MODE_PREC(mode) == GSL_PREC_DOUBLE) eval_order = cs->order; else eval_order = cs->order_sp; for(j = eval_order; j>=1; j--) { double temp = d; d = y2*d - dd + cs->c[j]; dd = temp; } if(result == 0) { return GSL_EFAULT; } else { result->val = y*d - dd + 0.5 * cs->c[0]; result->err = GSL_DBL_EPSILON * fabs(result->val) + fabs(cs->c[eval_order]); return GSL_SUCCESS; } } int gsl_sf_cheb_eval_deriv_impl(gsl_sf_cheb_series * cs, const double x, gsl_sf_result * result) { int j; double d = 0.0; double dd = 0.0; double y = (2.0*x - cs->a - cs->b) / (cs->b - cs->a); double y2 = 2.0 * y; if(cs->cp == (double *)0) gsl_sf_cheb_calc_deriv_impl(cs); for(j = cs->order; j>=1; j--) { double temp = d; d = y2*d - dd + cs->cp[j]; dd = temp; } if(result == 0) { return GSL_EFAULT; } else { result->val = y*d - dd + 0.5 * cs->cp[0]; result->err = GSL_DBL_EPSILON * fabs(result->val) + fabs(cs->cp[cs->order]); return GSL_SUCCESS; } } int gsl_sf_cheb_eval_integ_impl(gsl_sf_cheb_series * cs, const double x, gsl_sf_result * result) { int j; double d = 0.0; double dd = 0.0; double y = (2.0*x - cs->a - cs->b) / (cs->b - cs->a); double y2 = 2.0 * y; if(cs->ci == (double *)0) gsl_sf_cheb_calc_integ_impl(cs); for(j = cs->order; j>=1; j--) { double temp = d; d = y2*d - dd + cs->ci[j]; dd = temp; } if(result == 0) { return GSL_EFAULT; } else { result->val = y*d - dd + 0.5 * cs->ci[0]; result->err = GSL_DBL_EPSILON * fabs(result->val) + fabs(cs->ci[cs->order]); return GSL_SUCCESS; } } /*-*-*-*-*-*-*-*-*-*-*-* Functions w/ Error Handling *-*-*-*-*-*-*-*-*-*-*/ int gsl_sf_cheb_calc_e(gsl_sf_cheb_series * cs, double (*func)(double)) { int status = gsl_sf_cheb_calc_impl(cs, func); if(status != GSL_SUCCESS) { GSL_ERROR("gsl_sf_cheb_calc_e", status); } return status; } int gsl_sf_cheb_eval_e(const gsl_sf_cheb_series * cs, double x, gsl_sf_result * r) { int status = gsl_sf_cheb_eval_impl(cs, x, r); if(status != GSL_SUCCESS) { GSL_ERROR("gsl_sf_cheb_eval_e", status); } return status; } int gsl_sf_cheb_eval_n_e(const gsl_sf_cheb_series * cs, int order, double x, gsl_sf_result * r) { int status = gsl_sf_cheb_eval_n_impl(cs, order, x, r); if(status != GSL_SUCCESS) { GSL_ERROR("gsl_sf_cheb_eval_n_e", status); } return status; } int gsl_sf_cheb_eval_deriv_e(gsl_sf_cheb_series * cs, double x, gsl_sf_result * r) { int status = gsl_sf_cheb_eval_deriv_impl(cs, x, r); if(status != GSL_SUCCESS) { GSL_ERROR("gsl_sf_cheb_eval_deriv_e", status); } return status; } int gsl_sf_cheb_eval_integ_e(gsl_sf_cheb_series * cs, double x, gsl_sf_result * r) { int status = gsl_sf_cheb_eval_integ_impl(cs, x, r); if(status != GSL_SUCCESS) { GSL_ERROR("gsl_sf_cheb_eval_integ_e", status); } return status; } /*-*-*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*/ void gsl_sf_cheb_free(gsl_sf_cheb_series * cs) { if(cs != 0) { if(cs->c != 0) free(cs->c); free(cs); } }