|
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 |
}
|