package gve.calc.formula;
public class GoniomFunctions implements Function {
public GoniomFunctions() {}
public Part call(String funcname,Part args,Evaluator eval) {
if (funcname.equals("sin")) return computeSin(eval,args.evaluate(eval));
else if (funcname.equals("cos")) {
Part a = args.evaluate(eval);
if (a instanceof Real)
return new Real(Math.cos( ((Real)a).doubleValue ));
else if (a instanceof Interval) {
Interval intv = (Interval)a;
if (intv.high - intv.low > Math.PI*2) return new Interval(-1,1,false,false);
return intervalSin(intv.low+Math.PI/2,intv.high+Math.PI/2,intv.openLow,intv.openHigh);
}
}
return null;
}
private static Part computeSin(Evaluator ev,Object a) {
if (a instanceof Real)
return new Real(Math.sin( ((Real)a).doubleValue ));
else if (a instanceof Interval) {
Interval intv = (Interval)a;
if (intv.high - intv.low > Math.PI*2) return new Interval(-1,1,false,false);
return intervalSin(intv.low,intv.high,intv.openLow,intv.openHigh);
} else if (a instanceof OperatorUnion) {
OperatorUnion un = (OperatorUnion)a;
// sin(un.left u un.right) == sin(un.left) u sin(un.right)
return new OperatorUnion((Part)computeSin(ev,un.left),(Part)computeSin(ev,un.right));
} else return null;
}
private static Interval intervalSin(double low,double high,boolean openLow,boolean openHigh) {
if (Double.isInfinite(low) || Double.isInfinite(high))
return new Interval(-1,1,false,false);
{ // herleiden zodat low in [0,2pi[
double shift = low - (low % (Math.PI*2));
high = high - shift;
low = low - shift;
while (low < 0) {
high += Math.PI*2;
low += Math.PI*2;
}
}
if (low < Math.PI/2) {
if (high < Math.PI/2) {
return new Interval(Math.sin(low),Math.sin(high),openLow,openHigh);
} else if (high < Math.PI) {
double sinlow = Math.sin(low);
double sinhigh = Math.sin(high);
if (sinlow < sinhigh)
return new Interval(sinlow,1,openLow,false);
else return new Interval(sinhigh,1,openHigh,openLow);
} else if (high < Math.PI*3/2) {
return new Interval(Math.sin(high),1,openHigh,false);
} else return new Interval(-1,1,false,false);
} else if (low < Math.PI) {
if (high < Math.PI*3/2) return new Interval(Math.sin(high),Math.sin(low),openHigh,openLow);
else if (high < Math.PI*2) return new Interval(-1,Math.sin(low),false,openLow);
else if (high < Math.PI*5/2) {
double sinlow = Math.sin(low);
double sinhigh = Math.sin(high);
if (sinlow < sinhigh) return new Interval(-1,sinhigh,false,openHigh);
else return new Interval(-1,sinlow,false,openLow);
} else return new Interval(-1,1,false,false);
} else if (low < Math.PI*3/2) {
if (high < Math.PI*3/2) return new Interval(Math.sin(high),Math.sin(low),openHigh,openLow);
else if (high < Math.PI*2) {
double sinlow = Math.sin(low);
double sinhigh = Math.sin(high);
if (sinlow < sinhigh) return new Interval(-1,sinhigh,false,openHigh);
else return new Interval(-1,sinlow,false,openLow);
} else if (high < Math.PI*3.5) {
return new Interval(-1,Math.sin(high),false,openHigh);
} else return new Interval(-1,1,false,false);
} else { // low in ]3pi/2,2pi[
if (high < Math.PI*2.5) return new Interval(Math.sin(low),Math.sin(high),openLow,openHigh);
else if (high < Math.PI*3) return new Interval(Math.sin(low),1,openLow,false);
else if (high < Math.PI*3.5) {
double sinlow = Math.sin(low);
double sinhigh = Math.sin(high);
if (sinlow < sinhigh) return new Interval(sinlow,1,openLow,false);
else return new Interval(sinhigh,1,openHigh,false);
} else return new Interval(-1,1,false,false);
}
}
}