Post Reply 
(PC-12xx~14xx) qthsh Tanh-Sinh quadrature
04-11-2021, 03:05 AM (This post was last modified: 04-11-2021 01:07 PM by robve.)
Post: #48
RE: (PC-12xx~14xx) qthsh Tanh-Sinh quadrature
Here is my latest contribution with integrated Tanh-Sinh, Exp-Sinh, Sinh-Sinh rules. The Tanh-Sinh rule has the same Michalski & Mosig abscissas and weights, but reformulated to combine the three quadratures into one routine (see the updated doc for the formulas):

Code:
// Tanh-Sinh bounded [a,b], Exp-Sinh (one inf either side), Sinh-Sinh [-inf,inf]
double quad(double (*f)(double), double a, double b, double n, double eps) {
  const double tol = 10*eps;
  double c = 0, d = 1, s, sign = 1, e, v, h = 2;
  int k = 0, mode = 0; // Tanh-Sinh = 0, Exp-Sinh = 1, Sinh-Sinh = 2
  if (b < a) { // swap bounds
    v = b;
    b = a;
    a = v;
    sign = -1;
  }
  if (isfinite(a) && isfinite(b)) {
    c = (a+b)/2;
    d = (b-a)/2;
    s = f(c);
  }
  else if (isfinite(a)) {
    mode = 1; // Exp-Sinh
    c = a;
    s = f(a + 1);
  }
  else if (isfinite(b)) {
    mode = 1; // Exp-Sinh
    c = b;
    s = f(b - 1);
    d = -d;
    sign = -sign;
  }
  else {
    mode = 2; // Sinh-Sinh
    s = f(0);
  }
  do {
    double p = 0, q, t, eh;
    h /= 2;
    eh = exp(h);
    t = eh/2;
    if (k > 0)
      eh *= eh;
    do {
      double r, w, x, y;
      q = 0;
      r = w = exp(t-.25/t); // = exp(sinh(j*h))
      if (mode != 1) {      // if Tanh-Sinh or Sinh-Sinh
        w += 1/w;           // = 2*cosh(sinh(j*h))
        r -= 1/r;           // = 2*sinh(sinh(j*h))
        if (mode == 0) {    // if Tanh-Sinh
          r /= w;           // = tanh(sinh(j*h))
          w = 4/(w*w);      // = 1/cosh(sinh(j*h))^2
        }
        else {              // if Sinh-Sinh
          r /= 2;           // = sinh(sinh(j*h))
          w /= 2;           // = cosh(sinh(j*h))
        }
        x = c - d*r;
        if (x > a) {
          y = f(x);
          if (isfinite(y))  // if f(x) is finite, add to local sum
            q += y*w;
        }
      }
      else {                // Exp-Sinh
        x = c + d/r;
        if (x > a) {
          y = f(x);
          if (isfinite(y))  // if f(x) is finite, add to local sum
            q += y/w;
        }
      }
      x = c + d*r;
      if (x < b) {
        y = f(x);
        if (isfinite(y))    // if f(x) is finite, add to local sum
          q += y*w;
      }
      q *= t+.25/t;         // q *= cosh(j*h)
      p += q;
      t *= eh;
    } while (fabs(q) > eps*fabs(p));
    v = 2*s;
    s += p;
    ++k;
  } while (fabs(v-s) > tol*fabs(s) && k <= n);
  e = fabs(v-s)/(fabs(s)+eps);
  return sign*d*s*h; // result with estimated relative error e
}

This was highly optimized while keeping the code compact. Optimizations include strength reductions, branch eliminations, and variable reuse when possible to reduce CPU register pressure.

The partially optimized code for the inner loop is perhaps a bit easier to comprehend:

Code:
    t = eh = exp(h);
    if (k > 0)
      eh *= eh;
    do {
      double ch, u, r, x, w;
      ch = (t+1/t)/2; // = cosh(j*h)
      w = r = u = exp((t-1/t)/2); // = exp(sinh(j*h))
      if (mode != 1) {
        u += 1/u; // = 2*cosh(sinh(j*h))
        r -= 1/r;   // = 2*sinh(sinh(j*h))
        if (mode == 0) {
          r /= u; // = tanh(sinh(j*h))
          w = 4/(u*u); // = 1/cosh(sinh(j*h))
        }
        else {
          r /= 2;   // = sinh(sinh(j*h))
          w = u/2; // = cosh(sinh(j*h))
        }
      }
      x = d*r;
      q = 0;
      if (c+x < b) {
        double y = f(c+x);
        if (isfinite(y))
          q = y*w;
      }
      if (mode == 1)
        x = -d/r;
      if (c-x > a) {
        double y = f(c-x);
        if (isfinite(y))
          q += mode == 1 ? y/w : y*w;
      }
      q *= ch;
      p += q;
      t *= eh;
    } while (fabs(q) > eps*fabs(p));

I have verified the optimized routine with several examples, but more testing will be necessary to determine its numerical properties.

- Rob

Edit: minor change to fix mirrored bound checks.

"I count on old friends" -- HP 71B,Prime|Ti VOY200,Nspire CXII CAS|Casio fx-CG50...|Sharp PC-G850,E500,2500,1500,14xx,13xx,12xx...
Visit this user's website Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
RE: (PC-12xx~14xx) qthsh Tanh-Sinh quadrature - robve - 04-11-2021 03:05 AM



User(s) browsing this thread: 3 Guest(s)