using System;
namespace Legalsoft.Truffer
{
/// <summary>
/// 通过Ridders的多项式外推方法返回函数func在点x处的导数。
/// 输入值h作为估计的初始步长;它不需要很小,而是应为x上的增量,
/// 在此增量上func将发生实质性变化。误差估计导数返回为err。
/// Returns the derivative of a function func at a point x by Ridders' method of polynomial extrap-
/// olation.The value h is input as an estimated initial stepsize; it need not be small, but rather
/// should be an increment in x over which func changes substantially.An estimate of the error in
/// the derivative is returned as err.
/// </summary>
public class Dfridr
{
public Dfridr()
{
}
public static double dfridr(UniVarRealValueFun func, double x, double h, ref double err)
{
const int ntab = 10;
const double con = 1.4;
const double con2 = (con * con);
const double big = double.MaxValue;
const double safe = 2.0;
double ans = 0.0;
double[,] a = new double[ntab, ntab];
//if (h == 0.0)
if (Math.Abs(h) <= float.Epsilon)
{
throw new Exception("h must be nonzero in dfridr.");
}
double hh = h;
a[0, 0] = (func.funk(x + hh) - func.funk(x - hh)) / (2.0 * hh);
err = big;
for (int i = 1; i < ntab; i++)
{
hh /= con;
a[0, i] = (func.funk(x + hh) - func.funk(x - hh)) / (2.0 * hh);
double fac = con2;
for (int j = 1; j <= i; j++)
{
a[j, i] = (a[j - 1, i] * fac - a[j - 1, i - 1]) / (fac - 1.0);
fac = con2 * fac;
double errt = Math.Max(Math.Abs(a[j, i] - a[j - 1, i]), Math.Abs(a[j, i] - a[j - 1, i - 1]));
if (errt <= err)
{
err = errt;
ans = a[j, i];
}
}
if (Math.Abs(a[i, i] - a[i - 1, i - 1]) >= safe * err)
{
break;
}
}
return ans;
}
}
}