Blame integration/qng.c

Packit 67cb25
/* integration/qng.c
Packit 67cb25
 * 
Packit 67cb25
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 67cb25
 */
Packit 67cb25
Packit 67cb25
#include <config.h>
Packit 67cb25
#include <math.h>
Packit 67cb25
#include <float.h>
Packit 67cb25
#include <gsl/gsl_math.h>
Packit 67cb25
#include <gsl/gsl_errno.h>
Packit 67cb25
#include <gsl/gsl_integration.h>
Packit 67cb25
Packit 67cb25
#include "err.c"
Packit 67cb25
#include "qng.h"
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_integration_qng (const gsl_function *f,
Packit 67cb25
                     double a, double b,
Packit 67cb25
                     double epsabs, double epsrel,
Packit 67cb25
                     double * result, double * abserr, size_t * neval)
Packit 67cb25
{
Packit 67cb25
  double fv1[5], fv2[5], fv3[5], fv4[5];
Packit 67cb25
  double savfun[21];  /* array of function values which have been computed */
Packit 67cb25
  double res10, res21, res43, res87;    /* 10, 21, 43 and 87 point results */
Packit 67cb25
  double result_kronrod, err ; 
Packit 67cb25
  double resabs; /* approximation to the integral of abs(f) */
Packit 67cb25
  double resasc; /* approximation to the integral of abs(f-i/(b-a)) */
Packit 67cb25
Packit 67cb25
  const double half_length =  0.5 * (b - a);
Packit 67cb25
  const double abs_half_length = fabs (half_length);
Packit 67cb25
  const double center = 0.5 * (b + a);
Packit 67cb25
  const double f_center = GSL_FN_EVAL(f, center);
Packit 67cb25
Packit 67cb25
  int k ;
Packit 67cb25
Packit 67cb25
  if (epsabs <= 0 && (epsrel < 50 * GSL_DBL_EPSILON || epsrel < 0.5e-28))
Packit 67cb25
    {
Packit 67cb25
      * result = 0;
Packit 67cb25
      * abserr = 0;
Packit 67cb25
      * neval = 0;
Packit 67cb25
      GSL_ERROR ("tolerance cannot be achieved with given epsabs and epsrel",
Packit 67cb25
                 GSL_EBADTOL);
Packit 67cb25
    };
Packit 67cb25
Packit 67cb25
  /* Compute the integral using the 10- and 21-point formula. */
Packit 67cb25
Packit 67cb25
  res10 = 0;
Packit 67cb25
  res21 = w21b[5] * f_center;
Packit 67cb25
  resabs = w21b[5] * fabs (f_center);
Packit 67cb25
Packit 67cb25
  for (k = 0; k < 5; k++)
Packit 67cb25
    {
Packit 67cb25
      const double abscissa = half_length * x1[k];
Packit 67cb25
      const double fval1 = GSL_FN_EVAL(f, center + abscissa);
Packit 67cb25
      const double fval2 = GSL_FN_EVAL(f, center - abscissa);
Packit 67cb25
      const double fval = fval1 + fval2;
Packit 67cb25
      res10 += w10[k] * fval;
Packit 67cb25
      res21 += w21a[k] * fval;
Packit 67cb25
      resabs += w21a[k] * (fabs (fval1) + fabs (fval2));
Packit 67cb25
      savfun[k] = fval;
Packit 67cb25
      fv1[k] = fval1;
Packit 67cb25
      fv2[k] = fval2;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  for (k = 0; k < 5; k++)
Packit 67cb25
    {
Packit 67cb25
      const double abscissa = half_length * x2[k];
Packit 67cb25
      const double fval1 = GSL_FN_EVAL(f, center + abscissa);
Packit 67cb25
      const double fval2 = GSL_FN_EVAL(f, center - abscissa);
Packit 67cb25
      const double fval = fval1 + fval2;
Packit 67cb25
      res21 += w21b[k] * fval;
Packit 67cb25
      resabs += w21b[k] * (fabs (fval1) + fabs (fval2));
Packit 67cb25
      savfun[k + 5] = fval;
Packit 67cb25
      fv3[k] = fval1;
Packit 67cb25
      fv4[k] = fval2;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  resabs *= abs_half_length ;
Packit 67cb25
Packit 67cb25
  { 
Packit 67cb25
    const double mean = 0.5 * res21;
Packit 67cb25
  
Packit 67cb25
    resasc = w21b[5] * fabs (f_center - mean);
Packit 67cb25
    
Packit 67cb25
    for (k = 0; k < 5; k++)
Packit 67cb25
      {
Packit 67cb25
        resasc +=
Packit 67cb25
          (w21a[k] * (fabs (fv1[k] - mean) + fabs (fv2[k] - mean))
Packit 67cb25
          + w21b[k] * (fabs (fv3[k] - mean) + fabs (fv4[k] - mean)));
Packit 67cb25
      }
Packit 67cb25
    resasc *= abs_half_length ;
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  result_kronrod = res21 * half_length;
Packit 67cb25
  
Packit 67cb25
  err = rescale_error ((res21 - res10) * half_length, resabs, resasc) ;
Packit 67cb25
Packit 67cb25
  /*   test for convergence. */
Packit 67cb25
Packit 67cb25
  if (err < epsabs || err < epsrel * fabs (result_kronrod))
Packit 67cb25
    {
Packit 67cb25
      * result = result_kronrod ;
Packit 67cb25
      * abserr = err ;
Packit 67cb25
      * neval = 21;
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* compute the integral using the 43-point formula. */
Packit 67cb25
Packit 67cb25
  res43 = w43b[11] * f_center;
Packit 67cb25
Packit 67cb25
  for (k = 0; k < 10; k++)
Packit 67cb25
    {
Packit 67cb25
      res43 += savfun[k] * w43a[k];
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  for (k = 0; k < 11; k++)
Packit 67cb25
    {
Packit 67cb25
      const double abscissa = half_length * x3[k];
Packit 67cb25
      const double fval = (GSL_FN_EVAL(f, center + abscissa) 
Packit 67cb25
                           + GSL_FN_EVAL(f, center - abscissa));
Packit 67cb25
      res43 += fval * w43b[k];
Packit 67cb25
      savfun[k + 10] = fval;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /*  test for convergence */
Packit 67cb25
Packit 67cb25
  result_kronrod = res43 * half_length;
Packit 67cb25
  err = rescale_error ((res43 - res21) * half_length, resabs, resasc);
Packit 67cb25
Packit 67cb25
  if (err < epsabs || err < epsrel * fabs (result_kronrod))
Packit 67cb25
    {
Packit 67cb25
      * result = result_kronrod ;
Packit 67cb25
      * abserr = err ;
Packit 67cb25
      * neval = 43;
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* compute the integral using the 87-point formula. */
Packit 67cb25
Packit 67cb25
  res87 = w87b[22] * f_center;
Packit 67cb25
Packit 67cb25
  for (k = 0; k < 21; k++)
Packit 67cb25
    {
Packit 67cb25
      res87 += savfun[k] * w87a[k];
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  for (k = 0; k < 22; k++)
Packit 67cb25
    {
Packit 67cb25
      const double abscissa = half_length * x4[k];
Packit 67cb25
      res87 += w87b[k] * (GSL_FN_EVAL(f, center + abscissa) 
Packit 67cb25
                          + GSL_FN_EVAL(f, center - abscissa));
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /*  test for convergence */
Packit 67cb25
Packit 67cb25
  result_kronrod = res87 * half_length ;
Packit 67cb25
  
Packit 67cb25
  err = rescale_error ((res87 - res43) * half_length, resabs, resasc);
Packit 67cb25
  
Packit 67cb25
  if (err < epsabs || err < epsrel * fabs (result_kronrod))
Packit 67cb25
    {
Packit 67cb25
      * result = result_kronrod ;
Packit 67cb25
      * abserr = err ;
Packit 67cb25
      * neval = 87;
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* failed to converge */
Packit 67cb25
Packit 67cb25
  * result = result_kronrod ;
Packit 67cb25
  * abserr = err ;
Packit 67cb25
  * neval = 87;
Packit 67cb25
Packit 67cb25
  GSL_ERROR("failed to reach tolerance with highest-order rule", GSL_ETOL) ;
Packit 67cb25
}