So, I have this class, a root finder class for finding the places where a certain function is zero. I actaully have several descendants of this abstract class, each one with a different algorithm, but a bunch of code in the common abstract ancestor.
<font face="Courier New">package *******.rootfind;
public abstract class RootFind {
public double Epsilon=1e-6;
public Method convmethod;
public enum Method {
Relative,
Absolute,
Adaptive
};
private RootFunction R;
private double Yt;
public boolean IsConverged(double Y) {
return(ErrorAmount(Y)<Epsilon);
}
public double ErrorAmount(double Y) {
switch(convmethod) {
case Adaptive:
//If Y0<10, use difference
//else use relative difference
if(Math.abs(Yt)<10) {
return Math.abs(Y);
} else {
return Math.abs(Y)/Math.abs(Yt);
}
case Relative:
return Math.abs(Y)/Math.abs(Yt);
case Absolute:
return Math.abs(Y);
default:
throw new IllegalArgumentException("This can't happen! Strange enumeration value found");
}
}
protected abstract double Step() throws <font color="#ff0000">LuckOutException</font>;
protected abstract void init(double LXlo, double LXhi) throws <font color="#ff0000">LuckOutException</font>;
protected abstract double GetX();
protected abstract String PrintState();
private boolean verbose=false;
protected double eval(double x) throws <font color="#ff0000">LuckOutException</font> {
double result=R.F(x)-Yt;
if(IsConverged(result)) throw new <font color="#ff0000">LuckOutException</font>(x);
return result;
}
protected double evalp(double x){
return ((RootDeriv)R).dFdx(x);
}
public double Find(double LYt, double LXlo, double LXhi) throws ArithmeticException {
Yt=LYt;
try {
init(LXlo,LXhi);
int IterLimit=100;
int iters=0;
if(verbose)System.out.println(PrintState());
while(!IsConverged(Step())) {
if(verbose)System.out.println("Iter: "+iters+"\n"+PrintState());
iters++;
if(iters>IterLimit) throw new ArithmeticException("Convergence failed after "+IterLimit+" iterations");
}
return GetX();
} catch (<font color="#ff0000">LuckOutException</font> E) { return E.x; }
}
}
</font>
<font face="Courier New">package ***.rootfind;
/
Root-finding algorithm hit early convergence. Not really
an error. The RootFind framework traps this exception and
uses the double value in it as the independent variable.
/
public class LuckOutException extends Exception{
/
* Independent variable which happens to be sufficiently
* close to be a root.
*/
double x;
/
* Constructs a new LuckOutException with the value which
* happens to be a root.
* @param Lx Independent variable value
*/
public LuckOutException(double Lx) {
super(
"Algorithm hit early convergence at independent variable value: "+
Double.toString(Lx)
);
x=Lx;
}
}
<font face="Times New Roman">What's going on is that as this root finder hunts around, it may happen that it hits on a value of x which is the correct answer, purely by accident, before it is intended to converge. This is an ok situation, as all I care about is that the answer is correct.
So, I have a LuckOutException which is thrown in these cases. This exception has an extra field, where the algorithm sticks the correct answer when it hits it, and the catch block just returns that field as the correct answer.
1) Is this a bad way to do this?
2) If so, what should I do instead?
</font></font>