/// <summary> /// Differentiation of a one dimensional function after <c>f.Parameters[n]</c>. /// </summary> public static double dfdp(ParametricFunction2DDelegate f, double x, double y, IList <double> p, int n, out double abserr) { // adapted from gsl_diff_central /* Construct a divided difference table with a fairly large step * size to get a very rough estimate of f'''. Use this to estimate * the step size which will minimize the error in calculating f'. */ int i, k; double h = GSL_SQRT_DBL_EPSILON, a3, temp, pn = p[n], f0, f1; double[] a = new double[4], d = new double[4]; /* Algorithm based on description on pg. 204 of Conte and de Boor * (CdB) - coefficients of Newton form of polynomial of degree 3. */ for (i = 0; i < 4; i++) { a[i] = pn + (i - 2) * h; p[n] = a[i]; d[i] = f(x, y, p); p[n] = pn; } for (k = 1; k < 5; k++) { for (i = 0; i < 4 - k; i++) { d[i] = (d[i + 1] - d[i]) / (a[i + k] - a[i]); } } /* Adapt procedure described on pg. 282 of CdB to find best * value of step size. */ a3 = Math.Abs(d[0] + d[1] + d[2] + d[3]); if (a3 < 100 * GSL_SQRT_DBL_EPSILON) { a3 = 100 * GSL_SQRT_DBL_EPSILON; } h = Math.Pow(GSL_SQRT_DBL_EPSILON / (2 * a3), 1.0 / 3.0); if (h > 100 * GSL_SQRT_DBL_EPSILON) { h = 100 * GSL_SQRT_DBL_EPSILON; } abserr = Math.Abs(100.0 * a3 * h * h); temp = pn + h; GetH(pn, ref h, temp); p[n] = pn + h; f0 = f(x, y, p); p[n] = pn - h; f1 = f(x, y, p); return((f0 - f1) / (2 * h)); }
/// <summary> /// An alias for the routine dfdp. /// </summary> public static double diffp(ParametricFunction2DDelegate f, double x, double y, IList <double> p, int n, out double abserr) { return(dfdp(f, x, y, p, n, out abserr)); }