summaryrefslogtreecommitdiff
path: root/gsl-1.9/integration/qelg.c
diff options
context:
space:
mode:
Diffstat (limited to 'gsl-1.9/integration/qelg.c')
-rw-r--r--gsl-1.9/integration/qelg.c233
1 files changed, 233 insertions, 0 deletions
diff --git a/gsl-1.9/integration/qelg.c b/gsl-1.9/integration/qelg.c
new file mode 100644
index 0000000..8f45f64
--- /dev/null
+++ b/gsl-1.9/integration/qelg.c
@@ -0,0 +1,233 @@
+/* integration/qelg.c
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999, 2000 Brian Gough
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+struct extrapolation_table
+ {
+ size_t n;
+ double rlist2[52];
+ size_t nres;
+ double res3la[3];
+ };
+
+static void
+ initialise_table (struct extrapolation_table *table);
+
+static void
+ append_table (struct extrapolation_table *table, double y);
+
+static void
+initialise_table (struct extrapolation_table *table)
+{
+ table->n = 0;
+ table->nres = 0;
+}
+#ifdef JUNK
+static void
+initialise_table (struct extrapolation_table *table, double y)
+{
+ table->n = 0;
+ table->rlist2[0] = y;
+ table->nres = 0;
+}
+#endif
+static void
+append_table (struct extrapolation_table *table, double y)
+{
+ size_t n;
+ n = table->n;
+ table->rlist2[n] = y;
+ table->n++;
+}
+
+/* static inline void
+ qelg (size_t * n, double epstab[],
+ double * result, double * abserr,
+ double res3la[], size_t * nres); */
+
+static inline void
+ qelg (struct extrapolation_table *table, double *result, double *abserr);
+
+static inline void
+qelg (struct extrapolation_table *table, double *result, double *abserr)
+{
+ double *epstab = table->rlist2;
+ double *res3la = table->res3la;
+ const size_t n = table->n - 1;
+
+ const double current = epstab[n];
+
+ double absolute = GSL_DBL_MAX;
+ double relative = 5 * GSL_DBL_EPSILON * fabs (current);
+
+ const size_t newelm = n / 2;
+ const size_t n_orig = n;
+ size_t n_final = n;
+ size_t i;
+
+ const size_t nres_orig = table->nres;
+
+ *result = current;
+ *abserr = GSL_DBL_MAX;
+
+ if (n < 2)
+ {
+ *result = current;
+ *abserr = GSL_MAX_DBL (absolute, relative);
+ return;
+ }
+
+ epstab[n + 2] = epstab[n];
+ epstab[n] = GSL_DBL_MAX;
+
+ for (i = 0; i < newelm; i++)
+ {
+ double res = epstab[n - 2 * i + 2];
+ double e0 = epstab[n - 2 * i - 2];
+ double e1 = epstab[n - 2 * i - 1];
+ double e2 = res;
+
+ double e1abs = fabs (e1);
+ double delta2 = e2 - e1;
+ double err2 = fabs (delta2);
+ double tol2 = GSL_MAX_DBL (fabs (e2), e1abs) * GSL_DBL_EPSILON;
+ double delta3 = e1 - e0;
+ double err3 = fabs (delta3);
+ double tol3 = GSL_MAX_DBL (e1abs, fabs (e0)) * GSL_DBL_EPSILON;
+
+ double e3, delta1, err1, tol1, ss;
+
+ if (err2 <= tol2 && err3 <= tol3)
+ {
+ /* If e0, e1 and e2 are equal to within machine accuracy,
+ convergence is assumed. */
+
+ *result = res;
+ absolute = err2 + err3;
+ relative = 5 * GSL_DBL_EPSILON * fabs (res);
+ *abserr = GSL_MAX_DBL (absolute, relative);
+ return;
+ }
+
+ e3 = epstab[n - 2 * i];
+ epstab[n - 2 * i] = e1;
+ delta1 = e1 - e3;
+ err1 = fabs (delta1);
+ tol1 = GSL_MAX_DBL (e1abs, fabs (e3)) * GSL_DBL_EPSILON;
+
+ /* If two elements are very close to each other, omit a part of
+ the table by adjusting the value of n */
+
+ if (err1 <= tol1 || err2 <= tol2 || err3 <= tol3)
+ {
+ n_final = 2 * i;
+ break;
+ }
+
+ ss = (1 / delta1 + 1 / delta2) - 1 / delta3;
+
+ /* Test to detect irregular behaviour in the table, and
+ eventually omit a part of the table by adjusting the value of
+ n. */
+
+ if (fabs (ss * e1) <= 0.0001)
+ {
+ n_final = 2 * i;
+ break;
+ }
+
+ /* Compute a new element and eventually adjust the value of
+ result. */
+
+ res = e1 + 1 / ss;
+ epstab[n - 2 * i] = res;
+
+ {
+ const double error = err2 + fabs (res - e2) + err3;
+
+ if (error <= *abserr)
+ {
+ *abserr = error;
+ *result = res;
+ }
+ }
+ }
+
+ /* Shift the table */
+
+ {
+ const size_t limexp = 50 - 1;
+
+ if (n_final == limexp)
+ {
+ n_final = 2 * (limexp / 2);
+ }
+ }
+
+ if (n_orig % 2 == 1)
+ {
+ for (i = 0; i <= newelm; i++)
+ {
+ epstab[1 + i * 2] = epstab[i * 2 + 3];
+ }
+ }
+ else
+ {
+ for (i = 0; i <= newelm; i++)
+ {
+ epstab[i * 2] = epstab[i * 2 + 2];
+ }
+ }
+
+ if (n_orig != n_final)
+ {
+ for (i = 0; i <= n_final; i++)
+ {
+ epstab[i] = epstab[n_orig - n_final + i];
+ }
+ }
+
+ table->n = n_final + 1;
+
+ if (nres_orig < 3)
+ {
+ res3la[nres_orig] = *result;
+ *abserr = GSL_DBL_MAX;
+ }
+ else
+ { /* Compute error estimate */
+ *abserr = (fabs (*result - res3la[2]) + fabs (*result - res3la[1])
+ + fabs (*result - res3la[0]));
+
+ res3la[0] = res3la[1];
+ res3la[1] = res3la[2];
+ res3la[2] = *result;
+ }
+
+ /* In QUADPACK the variable table->nres is incremented at the top of
+ qelg, so it increases on every call. This leads to the array
+ res3la being accessed when its elements are still undefined, so I
+ have moved the update to this point so that its value more
+ useful. */
+
+ table->nres = nres_orig + 1;
+
+ *abserr = GSL_MAX_DBL (*abserr, 5 * GSL_DBL_EPSILON * fabs (*result));
+
+ return;
+}