/// <summary> /// Differentiation of a one dimensional function. /// </summary> public static double dfdx(IFunction1D f, double x, 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; 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] = x + (i - 2) * h; d[i] = f.f(a[i]); } 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 = x + h; GetH(x, ref h, temp); return((f.f(x + h) - f.f(x - h)) / (2 * h)); }
private static void gsl_integration_qk(int n, double[] xgk, double[] wg, double[] wgk, double[] fv1, double[] fv2, IFunction1D f, double a, double b, out double result, out double abserr, out double resabs, out double resasc, Workspace workspace) { double center = 0.5 * (a + b); double half_length = 0.5 * (b - a); double abs_half_length = (half_length); double f_center = f.f(center); double result_gauss = 0; double result_kronrod = f_center * wgk[n - 1]; double result_abs = 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.f(center - abscissa); double fval2 = f.f(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] * (Math.Abs(fval1) + Math.Abs(fval2)); } for (j = 0; j < n / 2; j++) { int jtwm1 = j * 2; double abscissa = half_length * xgk[jtwm1]; double fval1 = f.f(center - abscissa); double fval2 = f.f(center + abscissa); fv1[jtwm1] = fval1; fv2[jtwm1] = fval2; result_kronrod += wgk[jtwm1] * (fval1 + fval2); result_abs += wgk[jtwm1] * (Math.Abs(fval1) + Math.Abs(fval2)); } mean = result_kronrod * 0.5; result_asc = wgk[n - 1] * Math.Abs(f_center - mean); for (j = 0; j < n - 1; j++) { result_asc += wgk[j] * (Math.Abs(fv1[j] - mean) + 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 = rescale_error(err, result_abs, result_asc); }
/// <summary> /// Integration of a smooth one dimensional function. The integral is computed until the error is below either <c>epsabs</c> /// or <c>epsrel</c>. The algorithm is provided for fast integration of smooth functions. /// </summary> /// <param name="f">The function to integrate</param> /// <param name="a">The lower integration bound</param> /// <param name="b">The upper integration bound</param> /// <param name="epsabs">The desired absolute error</param> /// <param name="epsrel">The desired relative error</param> /// <param name="abserr">The estimated error of the result</param> /// <returns>The integral of the function</returns> public static double q(IFunction1D f, double a, double b, double epsabs, double epsrel, out double abserr) { double[] fv1 = new double[5], fv2 = new double[5], fv3 = new double[5], fv4 = new double[5]; double[] savfun = new double[21]; /* array of function values which have been computed */ double res10, res21, res43, res87; /* 10, 21, 43 and 87 point results */ double result_kronrod, result, err; double resabs; /* approximation to the integral of abs(f) */ double resasc; /* approximation to the integral of abs(f-i/(b-a)) */ double half_length = 0.5 * (b - a); double abs_half_length = Math.Abs(half_length); double center = 0.5 * (b + a); double f_center = f.f(center); int k; if (epsabs <= 0 && (epsrel < 50 * GSL_DBL_EPSILON || epsrel < 0.5e-28)) { abserr = 0; if (ThrowOnErrors) { throw new ArgumentException("errors too small"); } return(double.NaN); } /* Compute the integral using the 10- and 21-point formula. */ res10 = 0; res21 = w21b[5] * f_center; resabs = w21b[5] * Math.Abs(f_center); for (k = 0; k < 5; k++) { double abscissa = half_length * x1[k]; double fval1 = f.f(center + abscissa); double fval2 = f.f(center - abscissa); double fval = fval1 + fval2; res10 += w10[k] * fval; res21 += w21a[k] * fval; resabs += w21a[k] * (Math.Abs(fval1) + Math.Abs(fval2)); savfun[k] = fval; fv1[k] = fval1; fv2[k] = fval2; } for (k = 0; k < 5; k++) { double abscissa = half_length * x2[k]; double fval1 = f.f(center + abscissa); double fval2 = f.f(center - abscissa); double fval = fval1 + fval2; res21 += w21b[k] * fval; resabs += w21b[k] * (Math.Abs(fval1) + Math.Abs(fval2)); savfun[k + 5] = fval; fv3[k] = fval1; fv4[k] = fval2; } resabs *= abs_half_length; { double mean = 0.5 * res21; resasc = w21b[5] * Math.Abs(f_center - mean); for (k = 0; k < 5; k++) { resasc += (w21a[k] * (Math.Abs(fv1[k] - mean) + Math.Abs(fv2[k] - mean)) + w21b[k] * (Math.Abs(fv3[k] - mean) + Math.Abs(fv4[k] - mean))); } resasc *= abs_half_length; } result_kronrod = res21 * half_length; err = rescale_error((res21 - res10) * half_length, resabs, resasc); /* test for convergence. */ if (err < epsabs || err < epsrel * Math.Abs(result_kronrod)) { result = result_kronrod; abserr = err; return(result); } /* compute the integral using the 43-point formula. */ res43 = w43b[11] * f_center; for (k = 0; k < 10; k++) { res43 += savfun[k] * w43a[k]; } for (k = 0; k < 11; k++) { double abscissa = half_length * x3[k]; double fval = (f.f(center + abscissa) + f.f(center - abscissa)); res43 += fval * w43b[k]; savfun[k + 10] = fval; } /* test for convergence */ result_kronrod = res43 * half_length; err = rescale_error((res43 - res21) * half_length, resabs, resasc); if (err < epsabs || err < epsrel * Math.Abs(result_kronrod)) { result = result_kronrod; abserr = err; return(result); } /* compute the integral using the 87-point formula. */ res87 = w87b[22] * f_center; for (k = 0; k < 21; k++) { res87 += savfun[k] * w87a[k]; } for (k = 0; k < 22; k++) { double abscissa = half_length * x4[k]; res87 += w87b[k] * (f.f(center + abscissa) + f.f(center - abscissa)); } /* test for convergence */ result_kronrod = res87 * half_length; err = rescale_error((res87 - res43) * half_length, resabs, resasc); if (err < epsabs || err < epsrel * Math.Abs(result_kronrod)) { result = result_kronrod; abserr = err; return(result); } /* failed to converge */ result = result_kronrod; abserr = err; return(result); }