public static Double dekker(Function f, double a, double b, double tol, int nMax) { double fa = f.getValue(a); double fb = f.getValue(b); if (fa * fb >= 0.0) { System.out.println("Dekker method failed - root is not bracketed."); return null; } double bOld, fbOld; double temp; int n = 0; while (++n <= nMax) { if (Math.abs(fa) < Math.abs(fb)) { temp = a; a = b; b = temp; temp = fa; fa = fb; fb = temp; } bOld = b; fbOld = fb; if (Math.abs(fb - fa) > Constants.EPSILON) b -= fb * (b - a) / (fb - fa); else b = (a + b) / 2; fb = f.getValue(b); System.out.println(n + ". b = " + b + ", fb = " + fb); if ((Math.abs(fb) < Constants.EPSILON) || (Math.abs((b - a) / 2) < tol)) return b; if (fa * fb >= 0.0) { a = bOld; fa = fbOld; } } System.out.println("Dekker method failed - max number of iterations."); return b; }
/** * Root-finding algorithm combining the bisection method, the secant method and inverse quadratic * interpolation. It has the reliability of bisection but it can be as quick as some of the less * reliable methods. The algorithm tries to use the potentially fast-converging secant method or * inverse quadratic interpolation if possible, but it falls back to the more robust bisection * method if necessary. * * @param args */ public static Double brent(Function f, double a, double b, double tol, double delta, int nMax) { double fa = f.getValue(a); double fb = f.getValue(b); double fc = fa; if (fa * fb >= 0.0) { System.out.println("Brent method failed - root is not bracketed."); return null; } double c = a; double d = c; boolean mflag = true; double temp, s, fs; int n = 0; while (++n <= nMax) { if (Math.abs(fa) < Math.abs(fb)) { temp = a; a = b; b = temp; temp = fa; fa = fb; fb = temp; } if ((Math.abs(fc - fa) > Constants.EPSILON) && (Math.abs(fc - fb) > Constants.EPSILON)) s = a * fb * fc / ((fa - fb) * (fa - fc)) + b * fa * fc / ((fb - fa) * (fb - fc)) + c * fa * fb / ((fc - fa) * (fc - fb)); else s = b - fb * (b - a) / (fb - fa); if (((s <= (3 * a + b) / 4) || s >= b) || (mflag && ((Math.abs(s - b) >= Math.abs(b - c) / 2) || (Math.abs(b - c) < delta))) || (!mflag && ((Math.abs(s - b) >= Math.abs(c - d) / 2) || (Math.abs(c - d) < delta)))) { s = (a + b) / 2; mflag = true; } else mflag = false; fs = f.getValue(s); d = c; c = b; if (fa * fs < 0) { b = s; fb = fs; } else { a = s; fa = fs; } if (Math.abs(fa) < Math.abs(fb)) { temp = a; a = b; b = temp; temp = fa; fa = fb; fb = temp; } System.out.println(n + ". b = " + b + ", fb = " + fb); if ((Math.abs(fb) < Constants.EPSILON) || (Math.abs((b - a) / 2) < tol)) return b; } System.out.println("Brent method failed - max number of iterations."); return c; }
public static void main(String[] args) { double[] c = new double[4]; c[0] = -2; c[1] = -1; c[2] = 0; c[3] = 1; Function f = new Function(c); double root = RootFinding.brent(f, 1, 2, 0.000001, 0.00001, 25); System.out.println("Root at " + root + " with value " + f.getValue(root)); }
/** * Root-finding algorithm that starts with an initial guess which is reasonably close to the true * root, then the function is approximated by its tangent line (which can be computed using the * tools of calculus), and one computes the x-intercept of this tangent line (which is easily done * with elementary algebra). This x-intercept will typically be a better approximation to the * function's root than the original guess, and the method can be iterated. */ public static Double newton(Function f, double x, double x1, double tol, int nMax) { Function d = f.getDerivative(); int n = 0; double fx = f.getValue(x); double dx; while (++n <= nMax) { if ((Math.abs(fx) < Constants.EPSILON) || (Math.abs(x1 - x) < tol)) return x; dx = fx / d.getValue(x); x1 = x; x = x - dx; fx = f.getValue(x); } System.out.println("Newton method failed - max number of iterations."); return x; }
/** * Root-finding algorithm that uses a succession of roots of secant lines to better approximate a * root of a function f. The secant method can be thought of as a finite difference approximation * of Newton's method. However, the method was developed independently of Newton's method, and * predated the latter by over 3,000 years. */ public static Double secant(Function f, double x, double x1, double tol, int nMax) { int n = 0; double x2 = 0; double fx1 = f.getValue(x1); double fx = f.getValue(x); while (++n <= nMax) { if ((Math.abs(fx1) < Constants.EPSILON) || (Math.abs(x1 - x) < tol)) return x; x2 = x1 - fx1 * (x1 - x) / (fx1 - fx); x = x1; fx = fx1; x1 = x2; fx1 = f.getValue(x1); } System.out.println("Bisection method failed - max number of iterations."); return x; }
/** * Root-finding algorithm that repeatedly bisects an interval and then selects a subinterval in * which a root must lie for further processing. It is a very simple and robust method, but it is * also relatively slow. Because of this, it is often used to obtain a rough approximation to a * solution which is then used as a starting point for more rapidly converging methods The method * is also called the interval halving method, the binary search method, or the dichotomy method. */ public static Double bisection(Function f, double a, double b, double tol, int nMax) { double fa = f.getValue(a); double fb = f.getValue(b); double fc; if (fa * fb >= 0.0) { System.out.println("Bisection method failed - root is not bracketed."); return null; } double signA = Math.signum(fa); double c = 0; int n = 0; while (++n <= nMax) { c = (a + b) / 2; fc = f.getValue(c); System.out.println(n + ". c = " + c + ", fc = " + fc); if ((Math.abs(fc) < Constants.EPSILON) || ((b - a) / 2 < tol)) return c; if (Math.signum(fc) == signA) a = c; else b = c; } System.out.println("Bisection method failed - max number of iterations."); return c; }
/** * Root-finding algorithm that uses quadratic interpolation to approximate the inverse of f. This * algorithm is rarely used on its own, but it is important because it forms part of the popular * Brent's method. */ public static Double inverseQuadraticInterpolation( Function f, double x, double x1, double x2, double tol, int nMax) { int n = 0; double x0; double fx = f.getValue(x); double fx1 = f.getValue(x1); double fx2 = f.getValue(x2); while (++n <= nMax) { if ((Math.abs(fx) < Constants.EPSILON) || (Math.abs(x1 - x) < tol)) return x; x0 = x2 * fx1 * fx / ((fx2 - fx1) * (fx2 - fx)) + x1 * fx2 * fx / ((fx1 - fx2) * (fx1 - fx)) + x * fx2 * fx1 / (((fx - fx2) * (fx - fx1))); x2 = x1; fx2 = fx1; x1 = x; fx1 = fx; x = x0; fx = f.getValue(x); } System.out.println("Inverse Quadratic Interpolation method failed - max number of iterations."); return x; }