Blame integration/qelg.c

Packit 67cb25
/* integration/qelg.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
struct extrapolation_table
Packit 67cb25
  {
Packit 67cb25
    size_t n;
Packit 67cb25
    double rlist2[52];
Packit 67cb25
    size_t nres;
Packit 67cb25
    double res3la[3];
Packit 67cb25
  };
Packit 67cb25
Packit 67cb25
static void
Packit 67cb25
  initialise_table (struct extrapolation_table *table);
Packit 67cb25
Packit 67cb25
static void
Packit 67cb25
  append_table (struct extrapolation_table *table, double y);
Packit 67cb25
Packit 67cb25
static void
Packit 67cb25
initialise_table (struct extrapolation_table *table)
Packit 67cb25
{
Packit 67cb25
  table->n = 0;
Packit 67cb25
  table->nres = 0;
Packit 67cb25
}
Packit 67cb25
#ifdef JUNK
Packit 67cb25
static void
Packit 67cb25
initialise_table (struct extrapolation_table *table, double y)
Packit 67cb25
{
Packit 67cb25
  table->n = 0;
Packit 67cb25
  table->rlist2[0] = y;
Packit 67cb25
  table->nres = 0;
Packit 67cb25
}
Packit 67cb25
#endif
Packit 67cb25
static void
Packit 67cb25
append_table (struct extrapolation_table *table, double y)
Packit 67cb25
{
Packit 67cb25
  size_t n;
Packit 67cb25
  n = table->n;
Packit 67cb25
  table->rlist2[n] = y;
Packit 67cb25
  table->n++;
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
/* static inline void
Packit 67cb25
   qelg (size_t * n, double epstab[], 
Packit 67cb25
   double * result, double * abserr, 
Packit 67cb25
   double res3la[], size_t * nres); */
Packit 67cb25
Packit 67cb25
static inline void
Packit 67cb25
  qelg (struct extrapolation_table *table, double *result, double *abserr);
Packit 67cb25
Packit 67cb25
static inline void
Packit 67cb25
qelg (struct extrapolation_table *table, double *result, double *abserr)
Packit 67cb25
{
Packit 67cb25
  double *epstab = table->rlist2;
Packit 67cb25
  double *res3la = table->res3la;
Packit 67cb25
  const size_t n = table->n - 1;
Packit 67cb25
Packit 67cb25
  const double current = epstab[n];
Packit 67cb25
Packit 67cb25
  double absolute = GSL_DBL_MAX;
Packit 67cb25
  double relative = 5 * GSL_DBL_EPSILON * fabs (current);
Packit 67cb25
Packit 67cb25
  const size_t newelm = n / 2;
Packit 67cb25
  const size_t n_orig = n;
Packit 67cb25
  size_t n_final = n;
Packit 67cb25
  size_t i;
Packit 67cb25
Packit 67cb25
  const size_t nres_orig = table->nres;
Packit 67cb25
Packit 67cb25
  *result = current;
Packit 67cb25
  *abserr = GSL_DBL_MAX;
Packit 67cb25
Packit 67cb25
  if (n < 2)
Packit 67cb25
    {
Packit 67cb25
      *result = current;
Packit 67cb25
      *abserr = GSL_MAX_DBL (absolute, relative);
Packit 67cb25
      return;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  epstab[n + 2] = epstab[n];
Packit 67cb25
  epstab[n] = GSL_DBL_MAX;
Packit 67cb25
Packit 67cb25
  for (i = 0; i < newelm; i++)
Packit 67cb25
    {
Packit 67cb25
      double res = epstab[n - 2 * i + 2];
Packit 67cb25
      double e0 = epstab[n - 2 * i - 2];
Packit 67cb25
      double e1 = epstab[n - 2 * i - 1];
Packit 67cb25
      double e2 = res;
Packit 67cb25
Packit 67cb25
      double e1abs = fabs (e1);
Packit 67cb25
      double delta2 = e2 - e1;
Packit 67cb25
      double err2 = fabs (delta2);
Packit 67cb25
      double tol2 = GSL_MAX_DBL (fabs (e2), e1abs) * GSL_DBL_EPSILON;
Packit 67cb25
      double delta3 = e1 - e0;
Packit 67cb25
      double err3 = fabs (delta3);
Packit 67cb25
      double tol3 = GSL_MAX_DBL (e1abs, fabs (e0)) * GSL_DBL_EPSILON;
Packit 67cb25
Packit 67cb25
      double e3, delta1, err1, tol1, ss;
Packit 67cb25
Packit 67cb25
      if (err2 <= tol2 && err3 <= tol3)
Packit 67cb25
        {
Packit 67cb25
          /* If e0, e1 and e2 are equal to within machine accuracy,
Packit 67cb25
             convergence is assumed.  */
Packit 67cb25
Packit 67cb25
          *result = res;
Packit 67cb25
          absolute = err2 + err3;
Packit 67cb25
          relative = 5 * GSL_DBL_EPSILON * fabs (res);
Packit 67cb25
          *abserr = GSL_MAX_DBL (absolute, relative);
Packit 67cb25
          return;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      e3 = epstab[n - 2 * i];
Packit 67cb25
      epstab[n - 2 * i] = e1;
Packit 67cb25
      delta1 = e1 - e3;
Packit 67cb25
      err1 = fabs (delta1);
Packit 67cb25
      tol1 = GSL_MAX_DBL (e1abs, fabs (e3)) * GSL_DBL_EPSILON;
Packit 67cb25
Packit 67cb25
      /* If two elements are very close to each other, omit a part of
Packit 67cb25
         the table by adjusting the value of n */
Packit 67cb25
Packit 67cb25
      if (err1 <= tol1 || err2 <= tol2 || err3 <= tol3)
Packit 67cb25
        {
Packit 67cb25
          n_final = 2 * i;
Packit 67cb25
          break;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      ss = (1 / delta1 + 1 / delta2) - 1 / delta3;
Packit 67cb25
Packit 67cb25
      /* Test to detect irregular behaviour in the table, and
Packit 67cb25
         eventually omit a part of the table by adjusting the value of
Packit 67cb25
         n. */
Packit 67cb25
Packit 67cb25
      if (fabs (ss * e1) <= 0.0001)
Packit 67cb25
        {
Packit 67cb25
          n_final = 2 * i;
Packit 67cb25
          break;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      /* Compute a new element and eventually adjust the value of
Packit 67cb25
         result. */
Packit 67cb25
Packit 67cb25
      res = e1 + 1 / ss;
Packit 67cb25
      epstab[n - 2 * i] = res;
Packit 67cb25
Packit 67cb25
      {
Packit 67cb25
        const double error = err2 + fabs (res - e2) + err3;
Packit 67cb25
Packit 67cb25
        if (error <= *abserr)
Packit 67cb25
          {
Packit 67cb25
            *abserr = error;
Packit 67cb25
            *result = res;
Packit 67cb25
          }
Packit 67cb25
      }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* Shift the table */
Packit 67cb25
Packit 67cb25
  {
Packit 67cb25
    const size_t limexp = 50 - 1;
Packit 67cb25
Packit 67cb25
    if (n_final == limexp)
Packit 67cb25
      {
Packit 67cb25
        n_final = 2 * (limexp / 2);
Packit 67cb25
      }
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  if (n_orig % 2 == 1)
Packit 67cb25
    {
Packit 67cb25
      for (i = 0; i <= newelm; i++)
Packit 67cb25
        {
Packit 67cb25
          epstab[1 + i * 2] = epstab[i * 2 + 3];
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      for (i = 0; i <= newelm; i++)
Packit 67cb25
        {
Packit 67cb25
          epstab[i * 2] = epstab[i * 2 + 2];
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  if (n_orig != n_final)
Packit 67cb25
    {
Packit 67cb25
      for (i = 0; i <= n_final; i++)
Packit 67cb25
        {
Packit 67cb25
          epstab[i] = epstab[n_orig - n_final + i];
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  table->n = n_final + 1;
Packit 67cb25
Packit 67cb25
  if (nres_orig < 3)
Packit 67cb25
    {
Packit 67cb25
      res3la[nres_orig] = *result;
Packit 67cb25
      *abserr = GSL_DBL_MAX;
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {                           /* Compute error estimate */
Packit 67cb25
      *abserr = (fabs (*result - res3la[2]) + fabs (*result - res3la[1])
Packit 67cb25
                 + fabs (*result - res3la[0]));
Packit 67cb25
Packit 67cb25
      res3la[0] = res3la[1];
Packit 67cb25
      res3la[1] = res3la[2];
Packit 67cb25
      res3la[2] = *result;
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /* In QUADPACK the variable table->nres is incremented at the top of
Packit 67cb25
     qelg, so it increases on every call. This leads to the array
Packit 67cb25
     res3la being accessed when its elements are still undefined, so I
Packit 67cb25
     have moved the update to this point so that its value more
Packit 67cb25
     useful. */
Packit 67cb25
Packit 67cb25
  table->nres = nres_orig + 1;  
Packit 67cb25
Packit 67cb25
  *abserr = GSL_MAX_DBL (*abserr, 5 * GSL_DBL_EPSILON * fabs (*result));
Packit 67cb25
Packit 67cb25
  return;
Packit 67cb25
}