package tools;
// Simple Java Math Expression Evaluator
// Usage example: hmm
// java Evaluator "1+-min(-33,+4)*sin(0.5-0.1e-7) -atan2(3,4) +1/(0.051e-5)"
// 1+-min(-33,+4)*sin(0.5-0.1e-7)-atan2(3,4)+1/(0.051e-5) = 1960801.7782690835
//
// (c) 2008 Julian Bunn, Caltech. Julian.Bunn@caltech.edu
// You are free to use this code however you see fit. Please let me know if
// you find any bugs, or would like to suggest enhancements
import java.util.Vector;
public class CaltechEval {
String expression;
String[] Operators;
int[] OperatorsArgs;
boolean[] OperatorsLeftRight;
int[] OperatorsPrecedence;
int NOPERATORS;
public static void main(String[] args) {
if (args == null || args.length != 1) {
System.exit(0);
}
CaltechEval m = new CaltechEval(args[0]);
System.out.println(args[0].replace(" ", "") + " = " + m.evaluate());
}
public CaltechEval(String s) {
init();
expression = s.replace(" ", "");
}
private void init() {
NOPERATORS = 19;
Operators = new String[NOPERATORS];
OperatorsArgs = new int[NOPERATORS];
OperatorsLeftRight = new boolean[NOPERATORS];
OperatorsPrecedence = new int[NOPERATORS];
Operators[0] = "+";
OperatorsArgs[0] = 2;
OperatorsLeftRight[0] = true;
OperatorsPrecedence[0] = 2;
Operators[1] = "-";
OperatorsArgs[1] = 2;
OperatorsLeftRight[1] = true;
OperatorsPrecedence[1] = 2;
Operators[2] = "*";
OperatorsArgs[2] = 2;
OperatorsLeftRight[2] = true;
OperatorsPrecedence[2] = 3;
Operators[3] = "/";
OperatorsArgs[3] = 2;
OperatorsLeftRight[3] = true;
OperatorsPrecedence[3] = 3;
Operators[4] = "sin";
OperatorsArgs[4] = 1;
OperatorsLeftRight[4] = false;
OperatorsPrecedence[4] = 10;
Operators[5] = "cos";
OperatorsArgs[5] = 1;
OperatorsLeftRight[5] = false;
OperatorsPrecedence[5] = 10;
Operators[6] = "tan";
OperatorsArgs[6] = 1;
OperatorsLeftRight[6] = false;
OperatorsPrecedence[6] = 10;
Operators[7] = "exp";
OperatorsArgs[7] = 1;
OperatorsLeftRight[7] = false;
OperatorsPrecedence[7] = 10;
Operators[8] = "sqrt";
OperatorsArgs[8] = 1;
OperatorsLeftRight[8] = false;
OperatorsPrecedence[8] = 10;
Operators[9] = "asin";
OperatorsArgs[9] = 1;
OperatorsLeftRight[9] = false;
OperatorsPrecedence[9] = 10;
Operators[10] = "acos";
OperatorsArgs[10] = 1;
OperatorsLeftRight[10] = false;
OperatorsPrecedence[10] = 10;
Operators[11] = "atan";
OperatorsArgs[11] = 1;
OperatorsLeftRight[11] = false;
OperatorsPrecedence[11] = 10;
Operators[12] = "atan2";
OperatorsArgs[12] = 2;
OperatorsLeftRight[12] = false;
OperatorsPrecedence[12] = 10;
Operators[13] = "max";
OperatorsArgs[13] = 2;
OperatorsLeftRight[13] = false;
OperatorsPrecedence[13] = 10;
Operators[14] = "min";
OperatorsArgs[14] = 2;
OperatorsLeftRight[14] = false;
OperatorsPrecedence[14] = 10;
Operators[15] = ",";
OperatorsArgs[15] = 2;
OperatorsLeftRight[15] = true;
OperatorsPrecedence[15] = 1;
Operators[16] = "u";
OperatorsArgs[16] = 1;
OperatorsLeftRight[16] = false;
OperatorsPrecedence[16] = 4;
Operators[17] = "d";
OperatorsArgs[17] = 1;
OperatorsLeftRight[17] = false;
OperatorsPrecedence[17] = 4;
Operators[18] = "n";
OperatorsArgs[18] = 1;
OperatorsLeftRight[18] = false;
OperatorsPrecedence[18] = 11;
}
public double evaluate() {
return eval(expression);
}
private int getOperator(String op) {
for (int i = 0; i < NOPERATORS; i++) {
if (op.equals(Operators[i]) && op.length() == Operators[i].length()) {
return i;
}
}
return -1;
}
private double doOp(String op, double arg1, double arg2) {
if (op.equals("+")) {
return (arg1 + arg2);
}
if (op.equals("-")) {
return (arg1 - arg2);
}
if (op.equals("*")) {
return (arg1 * arg2);
}
if (op.equals("/")) {
return (arg1 / arg2);
}
if (op.equals("sin")) {
return Math.sin(arg1);
}
if (op.equals("cos")) {
return Math.cos(arg1);
}
if (op.equals("tan")) {
return Math.tan(arg1);
}
if (op.equals("exp")) {
return Math.exp(arg1);
}
if (op.equals("sqrt")) {
return Math.sqrt(arg1);
}
if (op.equals("asin")) {
return Math.asin(arg1);
}
if (op.equals("acos")) {
return Math.acos(arg1);
}
if (op.equals("atan")) {
return Math.atan(arg1);
}
if (op.equals("atan2")) {
return Math.atan2(arg1, arg2);
}
if (op.equals("max")) {
return (Math.max(arg1, arg2));
}
if (op.equals("min")) {
return (Math.min(arg1, arg2));
}
if (op.equals("u")) {
return (Math.ceil(arg1));
}
if (op.equals("d")) {
return (Math.floor(arg1));
}
if (op.equals("n")) {
return -arg1;
}
throw new RuntimeException("Invalid operator: " + op);
}
private boolean inOperand(char c) {
return (c >= '0' && c <= '9') || c == '.';
}
private Vector toTokens(String s) {
Vector tokenStrings = new Vector(1);
String operand = "";
String operator = "";
int nd = 0;
int nt = 0;
int i = 0;
while (i < s.length()) {
char c = s.charAt(i);
char cnext = ' ';
// System.out.println("Looking at " + c);
if (i < s.length() - 1) {
cnext = s.charAt(i + 1);
}
if (nt > 0 && operator.equals("atan") && c == '2') {
// System.out.println(" 1");
tokenStrings.addElement("atan2");
operator = "";
nt = 0;
i++;
} else if (inOperand(c)) {
// System.out.println(" 2");
operand += s.charAt(i);
nd++;
if (nt > 0) {
tokenStrings.addElement(operator);
}
nt = 0;
operator = "";
i++;
} else if (c == 'e' && nd > 0 && i < s.length() - 2
&& ((cnext == '+' || cnext == '-') || inOperand(cnext))) {
// System.out.println(" 3");
operand += c;
operand += cnext;
nd += 2;
nt = 0;
i += 2;
} else if (c == '(' || c == ')') {
// System.out.println(" 4");
if (nd > 0) {
tokenStrings.addElement(operand);
}
nd = 0;
operand = "";
if (nt > 0) {
tokenStrings.addElement(operator);
}
operator = "" + c;
tokenStrings.addElement(operator);
nt = 0;
operator = "";
i++;
} else {
// System.out.println(" 5");
if (nd > 0) {
tokenStrings.addElement(operand);
}
nd = 0;
operand = "";
operator += c;
if (operator.equals("+") || operator.equals("-")
|| operator.equals("*") || operator.equals("/")
|| operator.equals(",")) {
tokenStrings.addElement(operator);
nt = 0;
operator = "";
} else {
nt++;
}
i++;
}
}
if (nd > 0) {
tokenStrings.addElement(operand);
nt = 0;
}
if (nt > 0) {
tokenStrings.addElement(operator);
}
return tokenStrings;
}
private double eval(String s) {
Double D = new Double(0);
// System.out.println("Evaluating " + s);
Vector tokens = toTokens(s);
// System.out.print("Tokenized: ");
// for (int it = 0; it < tokens.size(); it++)
// {
// System.out.print((String) tokens.elementAt(it) + " ");
// }
// System.out.println("");
while (tokens.size() > 1) {
tokens = reduceTokens(tokens);
}
return D.parseDouble((String) tokens.elementAt(0));
}
public Vector reduceTokens(Vector tokens) {
Double D = new Double(0);
double leftValue = 0, rightValue1, rightValue2;
// System.out.print("Simplify Tokens :");
// for (int i = 0; i < tokens.size(); i++)
// System.out.print(" " + (String) tokens.elementAt(i));
// System.out.println("");
while (tokens.indexOf("(") != -1) {
int ib = tokens.indexOf("(");
Vector bracketTokens = new Vector();
int brackets = 1;
for (int it = ib + 1; it < tokens.size(); it++) {
String st = (String) tokens.elementAt(it);
if (st.equals(")")) {
brackets--;
} else if (st.equals("(")) {
brackets++;
}
if (brackets == 0) {
// System.out.println("Start brackets: " + ib +
// " end brackets " + it);
for (int i3 = ib + 1; i3 < it; i3++) {
bracketTokens.addElement(tokens.elementAt(i3));
}
int startsize = bracketTokens.size();
// System.out.println("call reduceTokens with");
// for (int i = 0; i < bracketTokens.size(); i++)
// System.out.println(" " +
// (String)bracketTokens.elementAt(i));
bracketTokens = reduceTokens(bracketTokens);
int endsize = bracketTokens.size();
//System.out.println("After reduce tokens Diff "+(startsize-
// endsize));
// for (int i = 0; i < bracketTokens.size(); i++)
// System.out.println(" " +
// (String)bracketTokens.elementAt(i));
int ip = ib;
for (int i3 = 0; i3 < bracketTokens.size(); i3++) {
tokens.setElementAt(bracketTokens.elementAt(i3), ip++);
}
for (int i = 0; i < startsize - endsize + 2; i++) {
tokens.removeElementAt(ip);
}
// System.out.println("Replaced tokens ");
// for (int i = 0; i < tokens.size(); i++)
// System.out.println(" " + (String)tokens.elementAt(i));
break;
}
}
// System.out.print("After bracket reduction: ");
// for (int i = 0; i < tokens.size(); i++);
// System.out.print(" " + (String) tokens.elementAt(i));
// System.out.println("");
}
// treat the operators in order of precedence
while (tokens.size() > 1) {
// System.out.print("Iterating expression: ");
// for (int i = 0; i < tokens.size(); i++)
// System.out.print(" " + (String) tokens.elementAt(i));
// System.out.println("");
int maxprec = 0;
int ipos = -1;
for (int it = 0; it < tokens.size(); it++) {
String st = (String) tokens.elementAt(it);
int iop = getOperator(st);
if (iop == -1) {
continue;
}
if (OperatorsPrecedence[iop] >= maxprec) {
maxprec = OperatorsPrecedence[iop];
ipos = it;
}
}
if (ipos == -1) {
return tokens; // for a simple list of operands
}
int it = ipos;
String st = (String) tokens.elementAt(it);
int iop = getOperator(st);
// System.out.println(" Precedence Operator: "+it+" " + st);
if (OperatorsLeftRight[iop]) {
if (!st.equals(",")) {
int ipt = it - 1;
if (it > 0) {
String stleft = (String) tokens.elementAt(it - 1);
if (getOperator(stleft) != -1) {
ipt = it;
leftValue = 0;
} else {
leftValue = D.parseDouble(stleft);
}
} else {
ipt = 0;
leftValue = 0.0;
}
String stright = (String) tokens.elementAt(it + 1);
rightValue1 = D.parseDouble(stright);
// System.out.print("DoOp " + leftValue + st + rightValue1);
double value = doOp(st, leftValue, rightValue1);
stright = "" + value;
// System.out.println(" = " + stright);
tokens.setElementAt(stright, ipt);
// System.out.println("After Op:");
tokens.removeElementAt(ipt + 1);
if (it > 0 && ipt != it) {
tokens.removeElementAt(ipt + 1);
}
// for (int i = 0; i < tokens.size(); i++)
// System.out.println(" " + (String)tokens.elementAt(i));
continue;
} else {
tokens.removeElementAt(it);
continue;
}
} else {
int nargs = OperatorsArgs[iop];
String stright = (String) tokens.elementAt(it + 1);
rightValue1 = D.parseDouble(stright);
rightValue2 = 0;
if (nargs > 1) {
stright = (String) tokens.elementAt(it + 2);
rightValue2 = D.parseDouble(stright);
}
// System.out.print("DoOp " + st + " "+
// rightValue1+" "+rightValue2);
double value = doOp(st, rightValue1, rightValue2);
stright = "" + value;
// System.out.println(" = " + stright);
tokens.setElementAt(stright, it);
// System.out.println("After Op:");
tokens.removeElementAt(it + 1);
if (nargs > 1) {
tokens.removeElementAt(it + 1);
}
// for (int i = 0; i < tokens.size(); i++)
// System.out.println(" " + (String)tokens.elementAt(i));
continue;
}
}
// System.out.print("Return from reduceTokens with: ");
// for (int i = 0; i < tokens.size(); i++) System.out.print(" " +
// (String)tokens.elementAt(i));
// System.out.println("");
return tokens;
}
}