Subversion Repositories mkgmap

Rev

Rev 3408 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2009 Christian Gawron
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *
 * Author: Christian Gawron
 * Create date: 03-Jul-2009
 */

package uk.me.parabola.mkgmap.reader.dem;

/**
 * Find zero of a function using Brent's method.
 */

public class Brent {
   
        public interface Function {
                public double eval(double x);
        }

    private static final double epsilon = 3.0e-10;

    public static double zero(Function f, double x1, double x2) {
                return zero(f, x1, x2, 1e-8, 100);
    }

        public static double zero(Function f, double x1, double x2, double tol, int maxit) {
                double a=x1, b=x2, c=x2;
                double fa=f.eval(a), fb=f.eval(b);

                if ((fa > 0.0 && fb > 0.0) || (fa < 0.0 && fb < 0.0))
                        throw new ArithmeticException("Root must be bracketed");

                double fc = fb;
                double d = 0;
                double e = 0;
                for (int iterations=0; iterations < maxit; iterations++) {
                        if ((fb > 0.0 && fc > 0.0) || (fb < 0.0 && fc < 0.0)) {
                                c=a;
                                fc=fa;
                                e=d=b-a;
                        }
                        if (Math.abs(fc) < Math.abs(fb)) {
                                a=b;
                                b=c;
                                c=a;
                                fa=fb;
                                fb=fc;
                                fc=fa;
                        }
                        double tolerance = 2.0 * epsilon * Math.abs(b) + 0.5 * tol;
                        double xm = 0.5 * (c - b);
                        if (Math.abs(xm) <= tolerance || fb == 0.0) return b;
                        if (Math.abs(e) >= tolerance && Math.abs(fa) > Math.abs(fb)) {
                                double s = fb / fa;
                                double p;
                                double q;
                                if (a == c) {
                                        p=2.0*xm*s;
                                        q=1.0-s;
                                } else {
                                        q=fa/fc;
                                        double r = fb / fc;
                                        p=s*(2.0*xm*q*(q-r)-(b-a)*(r-1.0));
                                        q=(q-1.0)*(r-1.0)*(s-1.0);
                                }
                                if (p > 0.0) q = -q;
                                p=Math.abs(p);
                                double min1 = 3.0 * xm * q - Math.abs(tolerance * q);
                                double min2 = Math.abs(e * q);
                                if (2.0*p < (min1 < min2 ? min1 : min2)) {
                                        e=d;
                                        d=p/q;
                                } else {
                                        d=xm;
                                        e=d;
                                }
                        } else {
                                d=xm;
                                e=d;
                        }
                        a=b;
                        fa=fb;
                        if (Math.abs(d) > tolerance)
                                b += d;
                        else
                                b += xm >= 0 ? tolerance : -tolerance;
                        fb=f.eval(b);
                }
                throw new ArithmeticException("Maximum number of iterations exceeded");
        }
}