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); } } }