/* Copyright 2011 frank asseg Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package de.congrace.exp4j; import java.util.Stack; /** * A {@link Token} for functions * * @author fas@congrace.de * */ class FunctionToken extends CalculationToken { /** * the functionNames that can be used in an expression * * @author ruckus * */ enum Function { ABS, ACOS, ASIN, ATAN, CBRT, CEIL, COS, COSH, EXP, EXPM1, FLOOR, ROUND, RANDOM, LOG, SIN, SINH, SQRT, TAN, TANH, LOG10 } private Function function; /** * construct a new {@link FunctionToken} * * @param value * the name of the function * @throws UnknownFunctionException * if an unknown function name is encountered */ FunctionToken(String value) throws UnknownFunctionException { super(value); try { function = Function.valueOf(value.toUpperCase()); } catch (IllegalArgumentException e) { throw new UnknownFunctionException(value); } if (function == null) { throw new UnknownFunctionException(value); } } /** * apply a function to a variable * * @param x * the value the function should be applied to * @return the result of the function */ public Variable applyFunction(Variable var) { // The names here are strictly unused, but are useful for debugging String name = function.name() + " result (#"+var.hashCode()+"), "; switch (var.getPrimary()) { case DOUBLE: name = "double "+name; double x = var.getDoubleValue(); return new Variable(name, applyFunction(x) ); case ARRAY: name = "array "+name; double[] input = var.getArrayValue(); double[] result = new double[input.length]; for (int i = 0; i < input.length; i++){ result[i] = applyFunction(input[i]); } return new Variable(name, result); default: return new Variable("Invalid"); } } /* * The actual function application on a double */ private double applyFunction(double x){ switch (function) { case ABS: return Math.abs(x); case ACOS: return Math.acos(x); case ASIN: return Math.asin(x); case ATAN: return Math.atan(x); case CBRT: return Math.cbrt(x); case CEIL: return Math.ceil(x); case COS: return Math.cos(x); case COSH: return Math.cosh(x); case EXP: return Math.exp(x); case EXPM1: return Math.expm1(x); case FLOOR: return Math.floor(x); case ROUND: return Math.round(x); case RANDOM: return Math.random()*x; case LOG: return Math.log(x); case LOG10: return Math.log10(x); case SIN: return Math.sin(x); case SINH: return Math.sinh(x); case SQRT: return Math.sqrt(x); case TAN: return Math.tan(x); case TANH: return Math.tanh(x); default: return Double.NaN; // should not happen ;) } } /** * * get the {@link Function} * * @return the correspoding {@link Function} */ Function getFunction() { return function; } @Override void mutateStackForCalculation(Stack<Variable> stack, VariableSet variableValues) { stack.push(this.applyFunction(stack.pop())); } @Override void mutateStackForInfixTranslation(Stack<Token> operatorStack, StringBuilder output) { operatorStack.push(this); } }