package com.towel.math; import java.util.HashMap; import java.util.Map; import com.towel.math.exp.Node; import com.towel.math.exp.Operator; import com.towel.math.exp.Operator.Operands; /** * * Represents and resolves a mathematical formula. This class accepts * expressions like '1+1' and '1*2'. It's also possible to use parenthesis, like * '1+(8*2)' and '1*(5+5)'. * <p> * The formula can have spaces; this class cleans it before start parsing. * <p> * With this new implementation it's possible to use functions, defined by * {@link Operator} enum. * <p> * To use, just put the name and the value inside parenthesis like 'cos(1)' * 'sin(1)', etc.. * <p> * With this, expressions can be complex, like '1-cos(8)+6*(tan(2)*log(1))'. * <p> * There's a especial operator 'random'. To use it: 'rnd(42)', this results in a * value between 0 and 41.99. * * @author Marcos A. Vasconcelos Junior * @see Operator * @see Node */ public class Expression { private String expression = null; private Map<String, Double> variables = new HashMap<String, Double>(); /** * Creates an empty Expression. You need to use * {@link #setExpression(String)} to assign a math expression string to. */ public Expression() { // do nothing } /** * Creates an Expression and assigns the math expression string. * * @param s * the expression string */ public Expression(String s) { setExpression(s); } /** * Adds a variable and its value in the Expression. * <p> * Something like this can be done: * * <pre> * Expression e = new Expression("(x+4)*x"); * e.setVariable("x", 7); * </pre> * * @param v * the variable name * @param val * the variable value */ public void setVariable(String v, double val) { variables.put(v, new Double(val)); } /** * Sets the expression. * * @param s * the expression string */ public void setExpression(String s) { expression = s; } /** * Resolve and returns the numerical value of this expression. * * @return the expression value */ public Double resolve() { if (expression == null) return null; try { return evaluate(new Node(this)); } catch (Exception e) { e.printStackTrace(); return null; } } private static Double evaluate(Node n) { if (n.hasOperator() && n.hasChild()) { if (n.getOperator().getType() == Operands.SINGLE) n.setValue(n.getOperator().resolve(evaluate(n.getLeft()), null)); else if (n.getOperator().getType() == Operands.DOUBLE) n.setValue(n.getOperator().resolve(evaluate(n.getLeft()), evaluate(n.getRight()))); } return n.getValue(); } /*** * Gets the variable's value. * * @param s * the variable's name * @return the variable's value */ public Double getVariable(String s) { return variables.get(s); } /** * Converts a string to a double or, if it's not possible, returns the value * of the variable with the given name. * * @param s * the string value or the variable name * @return the double value */ public Double getDouble(String s) { if (s == null) return null; try { return new Double(Double.parseDouble(s)); } catch (Exception e) { return getVariable(s); } } /** * @return a string representation of this expression */ public String getExpression() { return expression; } }