Browse Source

RootFinding: algorithm cosmetics

v2
Christoph Ruegg 14 years ago
parent
commit
ddac0a0b61
  1. 55
      src/Numerics/RootFinding/FindRoots.cs

55
src/Numerics/RootFinding/FindRoots.cs

@ -18,11 +18,9 @@ namespace MathNet.Numerics.RootFinding
/// </remarks> /// </remarks>
public static double BrentMethod(Func<double, double> f, double xmin, double xmax, double accuracy = 1e-8, int maxIterations = 100) public static double BrentMethod(Func<double, double> f, double xmin, double xmax, double accuracy = 1e-8, int maxIterations = 100)
{ {
double min1, min2; double xMid = 0;
double p, q, r, s, xAcc1, xMid = 0; double d = 0.0, e = 0.0;
double d = 0.0, e = 0.0;
// set up
double fxmin = f(xmin); double fxmin = f(xmin);
double fxmax = f(xmax); double fxmax = f(xmax);
double root = xmax; double root = xmax;
@ -30,13 +28,14 @@ namespace MathNet.Numerics.RootFinding
for (int i = 0; i <= maxIterations; i++) for (int i = 0; i <= maxIterations; i++)
{ {
// adjust bounds
if (Math.Sign(froot) == Math.Sign(fxmax)) if (Math.Sign(froot) == Math.Sign(fxmax))
{ {
// Rename xMin_, root_, xMax_ and adjust bounds
xmax = xmin; xmax = xmin;
fxmax = fxmin; fxmax = fxmin;
e = d = root - xmin; e = d = root - xmin;
} }
if (Math.Abs(fxmax) < Math.Abs(froot)) if (Math.Abs(fxmax) < Math.Abs(froot))
{ {
xmin = root; xmin = root;
@ -46,20 +45,22 @@ namespace MathNet.Numerics.RootFinding
froot = fxmax; froot = fxmax;
fxmax = fxmin; fxmax = fxmin;
} }
// Convergence check
xAcc1 = 2.0 * Precision.DoubleMachinePrecision * Math.Abs(root) + 0.5 * accuracy; // convergence check
double xAcc1 = 2.0 * Precision.DoubleMachinePrecision * Math.Abs(root) + 0.5 * accuracy;
xMid = (xmax - root) / 2.0; xMid = (xmax - root) / 2.0;
if (Math.Abs(xMid) <= xAcc1 || Close(froot, 0.0)) if (Math.Abs(xMid) <= xAcc1 || froot.AlmostEqualWithAbsoluteError(0, froot, accuracy))
{ {
return root; return root;
} }
if (Math.Abs(e) >= xAcc1 &&
Math.Abs(fxmin) > Math.Abs(froot))
{
if (Math.Abs(e) >= xAcc1 && Math.Abs(fxmin) > Math.Abs(froot))
{
// Attempt inverse quadratic interpolation // Attempt inverse quadratic interpolation
s = froot / fxmin; double s = froot / fxmin;
if (Close(xmin, xmax)) double p;
double q;
if (xmin.AlmostEqual(xmax))
{ {
p = 2.0 * xMid * s; p = 2.0 * xMid * s;
q = 1.0 - s; q = 1.0 - s;
@ -67,22 +68,27 @@ namespace MathNet.Numerics.RootFinding
else else
{ {
q = fxmin / fxmax; q = fxmin / fxmax;
r = froot / fxmax; double r = froot / fxmax;
p = s * (2.0 * xMid * q * (q - r) - (root - xmin) * (r - 1.0)); p = s * (2.0 * xMid * q * (q - r) - (root - xmin) * (r - 1.0));
q = (q - 1.0) * (r - 1.0) * (s - 1.0); q = (q - 1.0) * (r - 1.0) * (s - 1.0);
} }
if (p > 0.0) q = -q; // Check whether in bounds
if (p > 0.0)
{
// Check whether in bounds
q = -q;
}
p = Math.Abs(p); p = Math.Abs(p);
min1 = 3.0 * xMid * q - Math.Abs(xAcc1 * q); if (2.0 * p < Math.Min(3.0 * xMid * q - Math.Abs(xAcc1 * q), Math.Abs(e * q)))
min2 = Math.Abs(e * q);
if (2.0 * p < Math.Min(min1, min2))
{ {
e = d; // Accept interpolation // Accept interpolation
e = d;
d = p / q; d = p / q;
} }
else else
{ {
d = xMid; // Interpolation failed, use bisection // Interpolation failed, use bisection
d = xMid;
e = d; e = d;
} }
} }
@ -95,9 +101,13 @@ namespace MathNet.Numerics.RootFinding
xmin = root; xmin = root;
fxmin = froot; fxmin = froot;
if (Math.Abs(d) > xAcc1) if (Math.Abs(d) > xAcc1)
{
root += d; root += d;
}
else else
{
root += Sign(xAcc1, xMid); root += Sign(xAcc1, xMid);
}
froot = f(root); froot = f(root);
} }
@ -111,10 +121,5 @@ namespace MathNet.Numerics.RootFinding
{ {
return b >= 0 ? (a >= 0 ? a : -a) : (a >= 0 ? -a : a); return b >= 0 ? (a >= 0 ? a : -a) : (a >= 0 ? -a : a);
} }
static bool Close(double d1, double d2)
{
return Math.Abs(d1 - d2) <= double.Epsilon;
}
} }
} }

Loading…
Cancel
Save