private static void CentralDeriv(PZMath_f f, double x, double h, out double result, out double abserr_round, out double abserr_trunc) { /* 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.FN_EVAL(x - h); double fp1 = f.FN_EVAL(x + h); double fmh = f.FN_EVAL (x - h / 2); double fph = f.FN_EVAL (x + h / 2); double r3 = 0.5 * (fp1 - fm1); double r5 = (4.0 / 3.0) * (fph - fmh) - (1.0 / 3.0) * r3; double e3 = (System.Math.Abs(fp1) + System.Math.Abs(fm1)) * PZMath_machine.PZMath_DBL_EPSILON; double e5 = 2.0 * (System.Math.Abs(fph) + System.Math.Abs(fmh)) * PZMath_machine.PZMath_DBL_EPSILON + e3; double dy = System.Math.Max(System.Math.Abs(r3), System.Math.Abs(r5)) * System.Math.Abs(x) * PZMath_machine.PZMath_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. */ result = r5 / h; abserr_trunc = System.Math.Abs((r5 - r3) / h); /* Estimated truncation error O(h^2) */ abserr_round = System.Math.Abs(e5 / h) + dy; /* Rounding error (cancellations) */ }
static void QK(int n, double [] xgk, double [] wg, double [] wgk, double [] fv1, double [] fv2, PZMath_f f, double a, double b, ref double result, ref double abserr, ref double resabs, ref double resasc) { double center = 0.5 * (a + b); double half_length = 0.5 * (b - a); double abs_half_length = System.Math.Abs (half_length); double f_center = f.FN_EVAL(center); double result_gauss = 0; double result_kronrod = f_center * wgk[n - 1]; double result_abs = System.Math.Abs (result_kronrod); double result_asc = 0; double mean = 0, err = 0; int j; if (n % 2 == 0) result_gauss = f_center * wg[n / 2 - 1]; for (j = 0; j < (n - 1) / 2; j++) { int jtw = j * 2 + 1; /* j=1,2,3 jtw=2,4,6 */ double abscissa = half_length * xgk[jtw]; double fval1 = f.FN_EVAL (center - abscissa); double fval2 = f.FN_EVAL (center + abscissa); double fsum = fval1 + fval2; fv1[jtw] = fval1; fv2[jtw] = fval2; result_gauss += wg[j] * fsum; result_kronrod += wgk[jtw] * fsum; result_abs += wgk[jtw] * (System.Math.Abs (fval1) + System.Math.Abs (fval2)); } for (j = 0; j < n / 2; j++) { int jtwm1 = j * 2; double abscissa = half_length * xgk[jtwm1]; double fval1 = f.FN_EVAL (center - abscissa); double fval2 = f.FN_EVAL (center + abscissa); fv1[jtwm1] = fval1; fv2[jtwm1] = fval2; result_kronrod += wgk[jtwm1] * (fval1 + fval2); result_abs += wgk[jtwm1] * (System.Math.Abs (fval1) + System.Math.Abs (fval2)); } mean = result_kronrod * 0.5; result_asc = wgk[n - 1] * System.Math.Abs (f_center - mean); for (j = 0; j < n - 1; j++) result_asc += wgk[j] * (System.Math.Abs (fv1[j] - mean) + System.Math.Abs (fv2[j] - mean)); /* scale by the width of the integration region */ err = (result_kronrod - result_gauss) * half_length; result_kronrod *= half_length; result_abs *= abs_half_length; result_asc *= abs_half_length; result = result_kronrod; resabs = result_abs; resasc = result_asc; abserr = RescaleError (err, result_abs, result_asc); }