protected double rotational_derivative(double r) { DerivFunction df = (x) => this.sagitta(x); DerivResult result = Derivatives.central_derivative(df, r, 1e-4); return(result.result); }
public static DerivResult central_derivative(DerivFunction f, double x, double h) { double r_0; EvalResult res = central_deriv(f, x, h); double error = res.abserr_round + res.abserr_trunc; r_0 = res.result; if (res.abserr_round < res.abserr_trunc && (res.abserr_round > 0 && res.abserr_trunc > 0)) { double error_opt; /* Compute an optimised stepsize to minimize the total error, * using the scaling of the truncation error (O(h^2)) and * rounding error (O(1/h)). */ double h_opt = h * Math.Pow(res.abserr_round / (2.0 * res.abserr_trunc), 1.0 / 3.0); res = central_deriv(f, x, h_opt); error_opt = res.abserr_round + res.abserr_trunc; /* Check that the new error is smaller, and that the new derivative * is consistent with the error bounds of the original estimate. */ if (error_opt < error && Math.Abs(res.result - r_0) < 4.0 * error) { r_0 = res.result; error = error_opt; } } return(new DerivResult(r_0, error)); }
protected Vector2 base_derivative(Vector2 xy) { //double abserr; DerivFunction dxf = (x) => this.sagitta(new Vector2(x, xy.y())); DerivFunction dyf = (y) => this.sagitta(new Vector2(xy.x(), y)); DerivResult result = Derivatives.central_derivative(dxf, xy.x(), 1e-6); double dx = result.result; result = Derivatives.central_derivative(dyf, xy.y(), 1e-6); double dy = result.result; // TODO what do we do about error? return(new Vector2(dx, dy)); }
static EvalResult central_deriv(DerivFunction f, double x, double h) { /* Compute the derivative using the 5-point rule (x-h, x-h/2, x, * x+h/2, x+h). Note that the central point is not used. * * Compute the error using the difference between the 5-point and * the 3-point rule (x-h,x,x+h). Again the central point is not * used. */ double fm1 = f(x - h); double fp1 = f(x + h); double fmh = f(x - h / 2); double fph = f(x + h / 2); double r3 = 0.5 * (fp1 - fm1); double r5 = (4.0 / 3.0) * (fph - fmh) - (1.0 / 3.0) * r3; double e3 = (Math.Abs(fp1) + Math.Abs(fm1)) * GSL_DBL_EPSILON; double e5 = 2.0 * (Math.Abs(fph) + Math.Abs(fmh)) * GSL_DBL_EPSILON + e3; /* The next term is due to finite precision in x+h = O (eps * x) */ double dy = Math.Max(Math.Abs(r3 / h), Math.Abs(r5 / h)) * (Math.Abs(x) / h) * GSL_DBL_EPSILON; /* The truncation error in the r5 approximation itself is O(h^4). * However, for safety, we estimate the error from r5-r3, which is * O(h^2). By scaling h we will minimise this estimated error, not * the actual truncation error in r5. */ EvalResult result = new EvalResult(); result.result = r5 / h; result.abserr_trunc = Math.Abs((r5 - r3) / h); /* Estimated truncation error O(h^2) */ result.abserr_round = Math.Abs(e5 / h) + dy; /* Rounding error (cancellations) */ return(result); }