/* * FormulaVariableMath.java * * Created on July 21, 2006, 9:35 AM * * Copyright 2006 Lee Lofgern and Accounting Enhancements Inc 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 com.accountingenhancements.formula; import com.accountingenhancements.common.SupportParameters; import java.text.ParseException; /** * * @author Lee lofgren lofgren_opensource@accountingenhancements.com * @version 0.1009102006 */ public class FormulaVariableMath { /** Creates a new instance of FormulaVariableMath */ public FormulaVariableMath() { } /** *Apply unary operations to variable *@param unaryOperator FormulaVariable.TYPE_OPERATOR_UNARY_BIT_NOT or FormulaVariable.TYPE_OPERATOR_UNARY_NOT *@param variable the variable to which the unary operation is to be applied *@param variableList a list of variables, used to resolve variable if variable is of TYPE_VARIABLE, TYPE_FUNCTION, or TYPE_FORMULA *@param supportParameters a list of function parameters, used to resolve variable if variable is of TYPE_FORMULA or TYPE_FUNCTION *@param functionList a list of functions, used to resolve variable if variable is of TYPE_FORMULA or TYPE_FUNCTION *@param resolveEverythingAboveLevel reflects level at which TYPE_VARIABLE, TYPE_FUNCTION, and TYPE_FORMULA variables need to be re-solved. *@return FormulaVariable containing the result of the operation. If of the TYPE_OPERATOR_UNARY_NOT variety then a TYPE_BOOLEAN variable is returned. *@throws ParseException, ArithmeticException, ClassNotFoundException */ public static FormulaVariable solveUnaryOfVariable(int unaryOperator, FormulaVariable variable, FormulaVariableList variableList, SupportParameters supportParameters, FormulaFunctionList functionList, int resolveEverythingAboveLevel) throws ParseException, java.lang.ArithmeticException, ClassNotFoundException{ FormulaVariable result=null; String operatorSymbol; int type; String valueString; char[] charArray; if (variable==null)throw new java.lang.ArithmeticException("Unable to apply unaryOperator to a null value"); operatorSymbol=Integer.toString(unaryOperator); if(unaryOperator>=0&&unaryOperatornote, when doing multiplication or division with doubles (where both variables are TYPE_DOUBLE, precision becomes important.
* The lowest precision determines the number of digits to the right of the decimal point.
* Ex: Assuming the precision of 10 is 2 (Not overriden by user so 2 digits long) .234 * 10 = 2.3 therefore scale=1
* However, differing from real math, 12.345 * 10 = 123 (scale=0) instead of 120 (scale=-1) as regular math requires it because * I am assuming user intent is that accuracy is always at least to the 1's place.
* On a related note if one variable is a TYPE_LONG or TYPE_BOOLEAN , that variable defaults to a precision of 17, so in this case the precision ends up being the same as the precision of the only double value. * This means (Assuming scale of 12.345 is 5) that 12.345 * 10 = 123.45 and scale=2. When adding or subtracting with only 1 variable being TYPE_DOUBLE, the scale is the scale of the TYPE_DOUBLE. The TYPE_LONG scale==0 is ignored.
*The upshot is two TYPE_DOUBLEs can give you a different result than a TYPE_DOUBLE and TYPE_LONG given the same values. */ public static FormulaVariable applyOperatorToTwoVariables(FormulaVariable leftVariable, int operator, FormulaVariable rightVariable, FormulaVariableList variableList, SupportParameters supportParameters, FormulaFunctionList functionList, int resolveEverythingAboveLevel) throws ParseException, java.lang.ArithmeticException, ClassNotFoundException{ return applyOperatorToTwoVariables(null,leftVariable,operator,null,rightVariable,variableList,supportParameters,functionList,resolveEverythingAboveLevel); } /** *Please note, when doing multiplication or division with doubles (where both variables are TYPE_DOUBLE, precision becomes important.
* The lowest precision determines the number of digits to the right of the decimal point.
* Ex: Assuming the precision of 10 is 2 (Not overriden by user so 2 digits long) .234 * 10 = 2.3 therefore scale=1
* However, differing from real math, 12.345 * 10 = 123 (scale=0) instead of 120 (scale=-1) as regular math requires it because * I am assuming user intent is that accuracy is always at least to the 1's place.
* On a related note if one variable is a TYPE_LONG or TYPE_BOOLEAN , that variable defaults to a precision of 17, so in this case the precision ends up being the same as the precision of the only double value.
* This means (Assuming scale of 12.345 is 5) that 12.345 * 10 = 123.45 and scale=2. When adding or subtracting with only 1 variable being TYPE_DOUBLE, the scale is the scale of the TYPE_DOUBLE. The TYPE_LONG scale==0 is ignored.
*The upshot is two TYPE_DOUBLEs can give you a different result than a TYPE_DOUBLE and TYPE_LONG given the same values.
*When working with Dates, If either or both arguments is/are TYPE_STRING(s) but the detectVariableType() confirms that it/they are date(s), the string(s) will be treated as date(s).
*/ public static FormulaVariable applyOperatorToTwoVariables(Integer optionalLeftUnaryOperator,FormulaVariable leftVariable, int operator, Integer optionalRightUnaryOperator, FormulaVariable rightVariable, FormulaVariableList variableList, SupportParameters supportParameters, FormulaFunctionList functionList, int resolveEverythingAboveLevel) throws ParseException, java.lang.ArithmeticException, ClassNotFoundException{ FormulaVariable result=null; String leftType; String rightType; String operatorType; int tmpVal; long leftLong; long rightLong; long resultLong; String leftString; String rightString; String resultString; boolean leftBoolean; boolean rightBoolean; boolean resultBoolean; double leftDouble; double rightDouble; double resultDouble; java.util.Date leftDate; java.util.Date rightDate; java.util.Date resultDate; int level; int scale; int precision; //long to long, long to boolean, or boolean to long (boolean treated as 1 or 0) //String to String or either argument is a string //boolean to boolean //Date to Date (Compare or Subtract) Also Date to String, String to date, and String to String when the String contains a date. //Date to long, or Date to double (Add or Subtract) //double to double, double to long, or long to double operatorType=Integer.toString(operator); if(operator>-1&&operatorlevel)level=tmpVal; //Get String descriptions of operator, leftVariableType, and rightVariableType for error messages. operatorType=Integer.toString(operator); if(operator>-1&&operator-1&&tmpVal-1&&tmpVal=0&&operator=0&&operatorright)result=1; else result=0; } else if(operator==FormulaVariable.TYPE_OPERATOR_GREATER_THAN_OR_EQUAL) { if(left>=right)result=1; else result=0; } else if(operator==FormulaVariable.TYPE_OPERATOR_LESS_THAN) { if(left=0&&operator=0&&operator=0&&operatorjava.lang.Math.round(right*10000))result=1; else result=0; } else if(operator==FormulaVariable.TYPE_OPERATOR_GREATER_THAN_OR_EQUAL) { if(java.lang.Math.round(left*10000)>=java.lang.Math.round(right*10000))result=1; else result=0; } else if(operator==FormulaVariable.TYPE_OPERATOR_LESS_THAN) { if(java.lang.Math.round(left*10000) * Note: Ignores Time portion of date so new Date(1151064000000L) equals new Date(1151064006000L) *@param left left value *@param operator operation to be applied to left and right values *@param right right value *@return the result of the computation *@throws ArithmeticException if operation is invalid for these values. */ public static boolean applyOperatorToCompareDates(java.util.Date left , int operator, java.util.Date right)throws java.lang.ArithmeticException{ boolean result=false; java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyyMMdd"); String operatorSymbol=Integer.toString(operator); if(operator>=0&&operator0)result=true; else result=false; } else if(operator==FormulaVariable.TYPE_OPERATOR_GREATER_THAN_OR_EQUAL) { if(sdf.format(left).compareTo(sdf.format(right))>=0)result=true; else result=false; } else if(operator==FormulaVariable.TYPE_OPERATOR_LESS_THAN) { if(sdf.format(left).compareTo(sdf.format(right))<0)result=true; else result=false; } else if(operator==FormulaVariable.TYPE_OPERATOR_LESS_THAN_OR_EQUAL) { if(sdf.format(left).compareTo(sdf.format(right))<=0)result=true; else result=false; } else if(operator==FormulaVariable.TYPE_OPERATOR_MINUS) { throw new java.lang.ArithmeticException("Can't use TYPE_OPERATOR_MINUS to compare Dates"); } else if(operator==FormulaVariable.TYPE_OPERATOR_MODULUS) { throw new java.lang.ArithmeticException("Can't use TYPE_OPERATOR_MODULUS to compare Dates"); } else if(operator==FormulaVariable.TYPE_OPERATOR_MULTIPLY) { throw new java.lang.ArithmeticException("Can't use TYPE_OPERATOR_MULTIPLY to compare Dates"); } else if(operator==FormulaVariable.TYPE_OPERATOR_NOT_EQUAL) { if(sdf.format(left).compareTo(sdf.format(right))!=0)result=true; else result=false; } else if(operator==FormulaVariable.TYPE_OPERATOR_OR) { if(left!=null||right!=null)result=true; else result=false; } else if(operator==FormulaVariable.TYPE_OPERATOR_PLUS) { throw new java.lang.ArithmeticException("Can't use TYPE_OPERATOR_PLUS to compare dates"); } else throw new java.lang.ArithmeticException("Unrecognized operator: "+operatorSymbol); return result; } /** *@param left left value *@param operator operation to be applied to left and right values *@param right right value *@return the result of the computation *@throws ArithmeticException if operation is invalid for these values. */ public static boolean applyOperatorToCompareStrings(String left , int operator, String right)throws java.lang.ArithmeticException{ boolean result=false; String operatorSymbol=Integer.toString(operator); if(operator>=0&&operator0)result=true; else result=false; } else if(operator==FormulaVariable.TYPE_OPERATOR_GREATER_THAN_OR_EQUAL) { if(left.compareTo(right)>=0)result=true; else result=false; } else if(operator==FormulaVariable.TYPE_OPERATOR_LESS_THAN) { if(left.compareTo(right)<0)result=true; else result=false; } else if(operator==FormulaVariable.TYPE_OPERATOR_LESS_THAN_OR_EQUAL) { if(left.compareTo(right)<=0)result=true; else result=false; } else if(operator==FormulaVariable.TYPE_OPERATOR_MINUS) { throw new java.lang.ArithmeticException("Can't use TYPE_OPERATOR_MINUS to compare Strings"); } else if(operator==FormulaVariable.TYPE_OPERATOR_MODULUS) { throw new java.lang.ArithmeticException("Can't use TYPE_OPERATOR_MODULUS to compare Strings"); } else if(operator==FormulaVariable.TYPE_OPERATOR_MULTIPLY) { throw new java.lang.ArithmeticException("Can't use TYPE_OPERATOR_MULTIPLY to compare Strings"); } else if(operator==FormulaVariable.TYPE_OPERATOR_NOT_EQUAL) { if(left.compareTo(right)!=0)result=true; else result=false; } else if(operator==FormulaVariable.TYPE_OPERATOR_OR) { if(left!=null||right!=null)result=true; else result=false; } else if(operator==FormulaVariable.TYPE_OPERATOR_PLUS) { throw new java.lang.ArithmeticException("Can't use TYPE_OPERATOR_PLUS to compare Strings"); } else throw new java.lang.ArithmeticException("Unrecognized operator: "+operatorSymbol); return result; } /** *@param left left value *@param operator operation to be applied to left and right values. Only allowed to TYPE_OPERATOR_PLUS two strings *@param right right value *@return the result of the computation *@throws ArithmeticException if operation is invalid for these values. */ public static String applyOperatorToTwoVariables(String left , int operator, String right)throws java.lang.ArithmeticException{ String result=null; String operatorSymbol=Integer.toString(operator); if(operator>=0&&operator