String[] angleInput = {"sin", "cos", "tan", "sec", "csc", "cot"}, angleOutput = {"arcsin", "arccos", "arctan", "arcsec", "arccsc", "arccot"};
@Override
public ConsCell runOperation(String operation, ConsCell input) throws ParserException {
BigDec output = null;
ConsCell value = parser.run(input);
if (value.length() != 1 || value.getCarType() != ConsType.NUMBER)
throw new UndefinedResultException("The " + operation + " operation takes one decimal number for its arguments.", this);
BigDec inp = (BigDec) value.getCar();
//Special points (e.g. angles at which sin, cos, etc. have exact answers
if (operation.equals("cos") && ((parser.getAngleType().equals("Degrees") && inp.mod(new BigDec(180.0)).eq(new BigDec(90.0)))
|| (parser.getAngleType().equals("Radians") && inp.mod(new BigDec(Math.PI)).eq(new BigDec(Math.PI / 2))) || (parser.getAngleType().equals("Grads") && inp.mod(new BigDec(200.0)).eq(new BigDec(100.0))))) {
return new ConsCell(BigDec.ZERO, ConsType.NUMBER);
}
if ((operation.equals("sin") || operation.equals("tan")) && ((parser.getAngleType().equals("Degrees") && inp.mod(new BigDec(180.0)).eq(new BigDec(0.0)))
|| (parser.getAngleType().equals("Radians") && inp.mod(new BigDec(Math.PI)).eq(BigDec.ZERO)) || (parser.getAngleType().equals("Grads") && inp.mod(new BigDec(200.0)).eq(BigDec.ZERO)))) {
return new ConsCell(BigDec.ZERO, ConsType.NUMBER);
}
if (operation.equals("sin") && (parser.getAngleType().equals("Degrees") && inp.mod(new BigDec(360.0)).eq(new BigDec(30.0)) ||
parser.getAngleType().equals("Radians") && inp.eq(new BigDec(Math.PI / 6)) || parser.getAngleType().equals("Grads") && inp.mod(new BigDec(400.0)).eq(new BigDec(33.333333)))) {
return new ConsCell(new BigDec(0.5), ConsType.NUMBER);
}
if (operation.equals("cos") && (parser.getAngleType().equals("Degrees") && inp.mod(new BigDec(360.0)).eq(new BigDec(60.0)) ||
parser.getAngleType().equals("Radians") && inp.eq(new BigDec(Math.PI / 3)) || parser.getAngleType().equals("Grads") && inp.mod(new BigDec(400.0)).eq(new BigDec(66.666667)))) {
return new ConsCell(new BigDec(0.5), ConsType.NUMBER);
}
if (operation.equals("sin") && (parser.getAngleType().equals("Degrees") && inp.mod(new BigDec(360.0)).eq(new BigDec(210.0)) ||
parser.getAngleType().equals("Radians") && inp.eq(new BigDec(2 * Math.PI / 3)) ||
parser.getAngleType().equals("Grads") && inp.mod(new BigDec(400.0)).eq(new BigDec(233.333333)))) {
return new ConsCell(new BigDec(-0.5), ConsType.NUMBER);
}
if (operation.equals("cos") && (parser.getAngleType().equals("Degrees") && inp.mod(new BigDec(360.0)).eq(new BigDec(240.0)) ||
parser.getAngleType().equals("Radians") && inp.eq(new BigDec(4 * Math.PI / 3)) ||
parser.getAngleType().equals("Grads") && inp.mod(new BigDec(400.0)).eq(new BigDec(266.666667)))) {
return new ConsCell(new BigDec(-0.5), ConsType.NUMBER);
}
//End special points
for (String str : angleInput)
if (operation.equals(str)) {
inp = parser.getAngleType().toRadians(inp);
break;
}
if (((operation.equals("arcsin") || operation.equals("arccos")) && !(inp.gteq(new BigDec(-1.0)) && inp.lteq(new BigDec(1.0))))
|| ((operation.equals("arcsec") || operation.equals("arccsc")) && (inp.gteq(new BigDec(-1.0)) && inp.lteq(new BigDec(1.0))))
|| (operation.equals("arccosh") && (inp.lt(BigDec.ONE))) || (operation.equals("arctanh") && (inp.abs().gteq(BigDec.ONE)))
|| (operation.equals("arccoth") && (inp.abs().lteq(BigDec.ONE)))
|| (operation.equals("arcsech") && !(inp.gt(BigDec.ZERO) && inp.lteq(BigDec.ONE)))
|| (operation.equals("arccsch") && (inp.eq(BigDec.ZERO)))) {
return new ConsCell(BigDec.ZERO, ConsType.NUMBER);
}
while ((operation.equals("sec") || operation.equals("csc") || operation.equals("cot")) && inp.lt(BigDec.ZERO))
inp = inp.add(new BigDec(Math.PI * 2));
while ((operation.equals("sec") || operation.equals("csc") || operation.equals("cot")) && inp.gt(new BigDec(Math.PI * 2)))
inp = inp.subtract(new BigDec(Math.PI * 2));
if (operation.equals("sin"))
output = new BigDec(ApcomplexMath.sin(inp.getInternal()));
if (operation.equals("cos"))
output = new BigDec(ApcomplexMath.cos(inp.getInternal()));
if (operation.equals("tan"))
output = new BigDec(ApcomplexMath.tan(inp.getInternal()));
if (operation.equals("sec"))
output = BigDec.ONE.divide(new BigDec(ApcomplexMath.cos(inp.getInternal())));
if (operation.equals("csc"))
output = BigDec.ONE.divide(new BigDec(ApcomplexMath.sin(inp.getInternal())));
if (operation.equals("cot"))
output = BigDec.ONE.divide(new BigDec(ApcomplexMath.tan(inp.getInternal())));
if (operation.equals("arcsin"))
output = inp.eq(BigDec.ZERO) ? BigDec.ZERO : new BigDec(ApcomplexMath.asin(inp.getInternal()));
if (operation.equals("arccos"))
output = inp.eq(BigDec.ZERO) ? BigDec.ONE : new BigDec(ApcomplexMath.acos(inp.getInternal()));
if (operation.equals("arctan"))
output = inp.eq(BigDec.ZERO) ? BigDec.ZERO : new BigDec(ApcomplexMath.atan(inp.getInternal()));
if (operation.equals("arcsec"))
output = BigDec.ONE.divide(inp.eq(BigDec.ZERO) ? BigDec.ONE : new BigDec(ApcomplexMath.acos(inp.getInternal())));
if (operation.equals("arccsc"))
output = BigDec.ONE.divide(inp.eq(BigDec.ZERO) ? BigDec.ZERO : new BigDec(ApcomplexMath.asin(inp.getInternal())));
if (operation.equals("arccot"))
output = BigDec.ONE.divide(inp.eq(BigDec.ZERO) ? BigDec.ZERO : new BigDec(ApcomplexMath.atan(inp.getInternal())));
if (operation.equals("sinh"))
output = new BigDec(ApcomplexMath.sinh(inp.getInternal()));
if (operation.equals("cosh"))
output = new BigDec(ApcomplexMath.cosh(inp.getInternal()));
if (operation.equals("tanh"))
output = new BigDec(ApcomplexMath.tanh(inp.getInternal()));
if (operation.equals("sech"))
output = BigDec.ONE.divide(new BigDec(ApcomplexMath.cosh(inp.getInternal())));
if (operation.equals("csch"))
output = BigDec.ONE.divide(new BigDec(ApcomplexMath.sinh(inp.getInternal())));
if (operation.equals("coth"))
output = BigDec.ONE.divide(new BigDec(ApcomplexMath.tanh(inp.getInternal())));
if (operation.equals("arcsinh"))
return parser.run(new String("ln(x+(x^2+1)^(1/2))").replaceAll("x", "(" + inp.toString() + ")"));
if (operation.equals("arccosh"))
return parser.run(new String("ln(x+(x^2-1)^(1/2))").replaceAll("x", "(" + inp.toString() + ")"));
if (operation.equals("arctanh"))
return parser.run(new String("1/2*ln((1+x)/(1-x))").replaceAll("x", "(" + inp.toString() + ")"));
if (operation.equals("arcsech"))
return parser.run(new String("ln((1+(1-x^2)^(1/2))/x)").replaceAll("x", "(" + inp.toString() + ")"));
if (operation.equals("arccsch"))
return parser.run(new String("ln(1/x+((1+x^2)^(1/2))/(abs(x)))").replaceAll("x", "(" + inp.toString() + ")"));
if (operation.equals("arccoth"))
return parser.run(new String("1/2*ln((x+1)/(x-1))").replaceAll("x", "(" + inp.toString() + ")"));
if (output == null) //If the operation was not in this plugin
return null;
for (String str : angleOutput)
if (operation.equals(str)) {
output = parser.getAngleType().fromRadians(output);
break;
}
return new ConsCell(output, ConsType.NUMBER);
}