From f52e1b0daff3aadbe80cb9a92521756f97860eaf Mon Sep 17 00:00:00 2001 From: Avik Sengupta Date: Thu, 9 Jun 2005 18:34:57 +0000 Subject: [PATCH] New formula eval stuff - added functions and refactored, by Amol git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@353714 13f79535-47bb-0310-9956-ffa450edef68 --- .../record/formula/AbstractFunctionPtg.java | 4 +- .../poi/hssf/record/formula/eval/AddEval.java | 1 + .../hssf/record/formula/eval/DivideEval.java | 1 + .../hssf/record/formula/eval/ErrorEval.java | 565 +----------------- .../record/formula/eval/MultiplyEval.java | 1 + .../hssf/record/formula/eval/NumberEval.java | 2 + .../hssf/record/formula/eval/PowerEval.java | 1 + .../formula/eval/RelationalOperationEval.java | 2 +- .../hssf/record/formula/eval/StringEval.java | 2 + .../record/formula/eval/SubtractEval.java | 1 + .../record/formula/eval/UnaryMinusEval.java | 1 + .../record/formula/eval/UnaryPlusEval.java | 6 +- .../eval/ValueEvalToNumericXlator.java | 152 +++-- .../hssf/record/formula/functions/Abs.java | 19 +- .../hssf/record/formula/functions/Acos.java | 25 +- .../hssf/record/formula/functions/Acosh.java | 31 +- .../hssf/record/formula/functions/Asin.java | 25 +- .../hssf/record/formula/functions/Asinh.java | 28 +- .../hssf/record/formula/functions/Atan.java | 25 +- .../hssf/record/formula/functions/Atan2.java | 31 +- .../hssf/record/formula/functions/Atanh.java | 27 +- .../hssf/record/formula/functions/Avedev.java | 52 +- .../record/formula/functions/Average.java | 52 +- .../record/formula/functions/Averagea.java | 4 +- .../record/formula/functions/Ceiling.java | 62 +- .../hssf/record/formula/functions/Column.java | 40 ++ .../hssf/record/formula/functions/Combin.java | 62 +- .../record/formula/functions/Concatenate.java | 35 +- .../hssf/record/formula/functions/Cos.java | 21 +- .../hssf/record/formula/functions/Cosh.java | 25 +- .../record/formula/functions/Degrees.java | 14 - .../hssf/record/formula/functions/Devsq.java | 52 +- .../hssf/record/formula/functions/Dollar.java | 21 +- .../hssf/record/formula/functions/Even.java | 14 - .../hssf/record/formula/functions/Exact.java | 59 +- .../hssf/record/formula/functions/Exp.java | 21 +- .../hssf/record/formula/functions/Fact.java | 51 +- .../hssf/record/formula/functions/Floor.java | 57 +- .../hssf/record/formula/functions/Int.java | 25 +- .../record/formula/functions/IsError.java | 71 ++- .../record/formula/functions/Isblank.java | 67 ++- .../hssf/record/formula/functions/Large.java | 56 +- .../hssf/record/formula/functions/Len.java | 114 +++- .../poi/hssf/record/formula/functions/Ln.java | 20 +- .../hssf/record/formula/functions/Log.java | 26 +- .../hssf/record/formula/functions/Log10.java | 26 +- .../hssf/record/formula/functions/Lower.java | 40 +- .../hssf/record/formula/functions/Max.java | 43 +- .../hssf/record/formula/functions/Maxa.java | 45 +- .../hssf/record/formula/functions/Median.java | 52 +- .../hssf/record/formula/functions/Min.java | 43 +- .../hssf/record/formula/functions/Mina.java | 45 +- .../hssf/record/formula/functions/Mod.java | 62 +- .../hssf/record/formula/functions/Mode.java | 53 +- .../formula/functions/NumericFunction.java | 26 +- .../hssf/record/formula/functions/Odd.java | 14 - .../hssf/record/formula/functions/Power.java | 16 +- .../record/formula/functions/Product.java | 43 +- .../record/formula/functions/Radians.java | 14 - .../hssf/record/formula/functions/Round.java | 60 +- .../record/formula/functions/Rounddown.java | 60 +- .../record/formula/functions/Roundup.java | 62 +- .../hssf/record/formula/functions/Row.java | 42 +- .../hssf/record/formula/functions/Sign.java | 20 +- .../hssf/record/formula/functions/Sin.java | 25 +- .../hssf/record/formula/functions/Sinh.java | 29 +- .../hssf/record/formula/functions/Small.java | 56 +- .../hssf/record/formula/functions/Sqrt.java | 25 +- .../hssf/record/formula/functions/Stdev.java | 52 +- .../hssf/record/formula/functions/Sum.java | 43 +- .../record/formula/functions/Sumproduct.java | 4 +- .../hssf/record/formula/functions/Sumsq.java | 45 +- .../record/formula/functions/Sumx2my2.java | 38 +- .../record/formula/functions/Sumx2py2.java | 38 +- .../record/formula/functions/Sumxmy2.java | 38 +- .../poi/hssf/record/formula/functions/T.java | 26 +- .../hssf/record/formula/functions/Tan.java | 25 +- .../hssf/record/formula/functions/Tanh.java | 29 +- .../hssf/record/formula/functions/Upper.java | 40 +- .../hssf/usermodel/HSSFFormulaEvaluator.java | 6 +- .../poi/hssf/data/FormulaEvalTestData.xls | Bin 92160 -> 121856 bytes .../formula/eval/GenericFormulaTestCase.java | 19 +- .../formula/functions/TestEverything.java | 1 + 83 files changed, 2091 insertions(+), 1185 deletions(-) diff --git a/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java b/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java index 24d012577a..4f121ab0c2 100644 --- a/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java @@ -676,8 +676,8 @@ public abstract class AbstractFunctionPtg extends OperationPtg { functionData[209][0]=new Byte(Ptg.CLASS_VALUE);functionData[209][1]=new byte[] {Ptg.CLASS_VALUE};functionData[209][2]=new Integer(2); functionData[210][0]=new Byte(Ptg.CLASS_VALUE);functionData[210][1]=new byte[] {Ptg.CLASS_VALUE};functionData[210][2]=new Integer(2); functionData[211][0]=new Byte(Ptg.CLASS_VALUE);functionData[211][1]=new byte[] {Ptg.CLASS_VALUE};functionData[211][2]=new Integer(1); - functionData[212][0]=new Byte(Ptg.CLASS_VALUE);functionData[212][1]=new byte[] {Ptg.CLASS_VALUE};functionData[212][2]=new Integer(1); - functionData[213][0]=new Byte(Ptg.CLASS_VALUE);functionData[213][1]=new byte[] {Ptg.CLASS_REF};functionData[213][2]=new Integer(-1); + functionData[212][0]=new Byte(Ptg.CLASS_VALUE);functionData[212][1]=new byte[] {Ptg.CLASS_VALUE};functionData[212][2]=new Integer(2); + functionData[213][0]=new Byte(Ptg.CLASS_VALUE);functionData[213][1]=new byte[] {Ptg.CLASS_REF};functionData[213][2]=new Integer(2); functionData[214][0]=new Byte(Ptg.CLASS_VALUE);functionData[214][1]=new byte[] {Ptg.CLASS_VALUE};functionData[214][2]=new Integer(-1); diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/AddEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/AddEval.java index bc993a662f..0947659c39 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/AddEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/AddEval.java @@ -31,6 +31,7 @@ public class AddEval extends NumericOperationEval { | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED | ValueEvalToNumericXlator.STRING_IS_PARSED + | ValueEvalToNumericXlator.REF_STRING_IS_PARSED )); public AddEval(Ptg ptg) { diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/DivideEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/DivideEval.java index 3b9d193bc1..38803c9689 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/DivideEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/DivideEval.java @@ -22,6 +22,7 @@ public class DivideEval extends NumericOperationEval { | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED | ValueEvalToNumericXlator.STRING_IS_PARSED + | ValueEvalToNumericXlator.REF_STRING_IS_PARSED )); public DivideEval(Ptg ptg) { diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/ErrorEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/ErrorEval.java index e1c8a7fcc0..a32db96863 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/ErrorEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/ErrorEval.java @@ -7,576 +7,15 @@ package org.apache.poi.hssf.record.formula.eval; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * - * Error code reference from OpenOffice documentation:
- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
- *

- * Error Code - *

- *
- *

- * Message - *

- *
- *

- * Explanation - *

- *
- *

- * 501 - *

- *
- *

- * Invalid character - *

- *
- *

- * Character in a formula is not valid, for example, "=1Eq" instead of - * "=1E2". - *

- *
- *

- * 502 - *

- *
- *

- * Invalid argument - *

- *
- *

- * Function argument is not valid, for example, a negative number for the root - * function. - *

- *
- *

- * 503 - *

- *
- *

- * Invalid floating point operation - *

- *
- *

- * Division by 0, or another calculation that results in an overflow of the - * defined value range. - *

- *
- *

- * 504 - *

- *
- *

- * Parameter list error - *

- *
- *

- * Function parameter is not valid, for example, text instead of a number, or a - * domain reference instead of cell reference. - *

- *
- *

- * 505 - *

- *
- *

- * Internal syntax error - *

- *
- *

- * Not used - *

- *
- *

- * 506 - *

- *
- *

- * Invalid semicolon - *

- *
- *

- * Not used - *

- *
- *

- * 507 - *

- *
- *

- * Error: Pair missing - *

- *
- *

- * Not used - *

- *
- *

- * 508 - *

- *
- *

- * Error: Pair missing - *

- *
- *

- * Missing bracket, for example, closing brackets, but no opening brackets - *

- *
- *

- * 509 - *

- *
- *

- * Missing operator - *

- *
- *

- * Operator is missing, for example, "=2(3+4) * ", where the operator - * between "2" and "(" is missing. - *

- *
- *

- * 510 - *

- *
- *

- * Missing variable - *

- *
- *

- * Variable is missing, for example when two operators are together - * "=1+*2". - *

- *
- *

- * 511 - *

- *
- *

- * Missing variable - *

- *
- *

- * Function requires more variables than are provided, for example, AND() and - * OR(). - *

- *
- *

- * 512 - *

- *
- *

- * Formula overflow - *

- *
- *

- * Compiler: the total number of internal tokens, (that is, operators, - * variables, brackets) in the formula exceeds 512. Interpreter: the - * total number of matrices that the formula creates exceeds 150. This includes - * basic functions that receive too large an array as a parameter (max. 0xFFFE, - * for example, 65534 bytes). - *

- *
- *

- * 513 - *

- *
- *

- * String overflow - *

- *
- *

- * Compiler: an identifier in the formula exceeds 64 KB in size. - * Interpreter: a result of a string operation exceeds 64 KB in size. - *

- *
- *

- * 514 - *

- *
- *

- * Internal overflow - *

- *
- *

- * Sort operation attempted on too much numerical data (max. 100000) or a - * calculation stack overflow. - *

- *
- *

- * 515 - *

- *
- *

- * Internal syntax error - *

- *
- *

- * Not used - *

- *
- *

- * 516 - *

- *
- *

- * Internal syntax error - *

- *
- *

- * Matrix is expected on the calculation stack, but is not available. - *

- *
- *

- * 517 - *

- *
- *

- * Internal syntax error - *

- *
- *

- * Unknown code, for example, a document with a newer function is loaded in an - * older version that does not contain the function. - *

- *
- *

- * 518 - *

- *
- *

- * Internal syntax error - *

- *
- *

- * Variable is not available - *

- *
- *

- * 519 - *

- *
- *

- * No result (#VALUE is in the cell rather than Err:519!) - *

- *
- *

- * Formula yields a value that does not corresponds to the definition, or a cell - * that is referenced in the formula contains text instead of a number. - *

- *
- *

- * 520 - *

- *
- *

- * Internal syntax error - *

- *
- *

- * Compiler creates an unknown compiler code. - *

- *
- *

- * 521 - *

- *
- *

- * Internal syntax error - *

- *
- *

- * No result. - *

- *
- *

- * 522 - *

- *
- *

- * Circular reference - *

- *
- *

- * Formula refers directly or indirectly to itself and the iterations option is - * not selected under Tools - Options - Table Document - Calculate. - *

- *
- *

- * 523 - *

- *
- *

- * The calculation procedure does not converge - *

- *
- *

- * Financial statistics function missed a targeted value or iterations of - * circular references do not reach the minimum change within the maximum steps - * that are set. - *

- *
- *

- * 524 - *

- *
- *

- * invalid references - * (instead of Err:524 cell contains #REF) - *

- *
- *

- * Compiler: a column or row description name could not be resolved. - * Interpreter: in a formula, the column, row, or sheet that contains a - * referenced cell is missing. - *

- *
- *

- * 525 - *

- *
- *

- * invalid names (instead of - * Err:525 cell contains #NAME?) - *

- *
- *

- * An identifier could not be evaluated, for example, no valid reference, no - * valid domain name, no column/row label, no macro, incorrect decimal divider, - * add-in not found. - *

- *
- *

- * 526 - *

- *
- *

- * Internal syntax error - *

- *
- *

- * Obsolete, no longer used, but could come from old documents if the result is - * a formula from a domain. - *

- *
- *

- * 527 - *

- *
- *

- * Internal overflow - *

- *
- *

- * Interpreter: References, such as when a cell references a cell, are - * too encapsulated. - *

- *
- * */ public class ErrorEval implements ValueEval { private int errorCode; - // Oo std error codes - public static final ErrorEval ERROR_501 = new ErrorEval(501); - public static final ErrorEval ERROR_502 = new ErrorEval(502); + public static final ErrorEval NAME_INVALID = new ErrorEval(525); - public static final ErrorEval ERROR_503 = new ErrorEval(503); - - public static final ErrorEval ERROR_504 = new ErrorEval(504); - - public static final ErrorEval ERROR_505 = new ErrorEval(505); - - public static final ErrorEval ERROR_506 = new ErrorEval(506); - - public static final ErrorEval ERROR_507 = new ErrorEval(507); - - public static final ErrorEval ERROR_508 = new ErrorEval(508); - - public static final ErrorEval ERROR_509 = new ErrorEval(509); - - public static final ErrorEval ERROR_510 = new ErrorEval(510); - - public static final ErrorEval ERROR_511 = new ErrorEval(511); - - public static final ErrorEval ERROR_512 = new ErrorEval(512); - - public static final ErrorEval ERROR_513 = new ErrorEval(513); - - public static final ErrorEval ERROR_514 = new ErrorEval(514); - - public static final ErrorEval ERROR_515 = new ErrorEval(515); - - public static final ErrorEval ERROR_516 = new ErrorEval(516); - - public static final ErrorEval ERROR_517 = new ErrorEval(517); - - public static final ErrorEval ERROR_518 = new ErrorEval(518); - - public static final ErrorEval ERROR_519 = new ErrorEval(519); - - public static final ErrorEval ERROR_520 = new ErrorEval(520); - - public static final ErrorEval ERROR_521 = new ErrorEval(521); - - public static final ErrorEval ERROR_522 = new ErrorEval(522); - - public static final ErrorEval ERROR_523 = new ErrorEval(523); - - public static final ErrorEval ERROR_524 = new ErrorEval(524); - - public static final ErrorEval ERROR_525 = new ErrorEval(525); - - public static final ErrorEval ERROR_526 = new ErrorEval(526); - - public static final ErrorEval ERROR_527 = new ErrorEval(527); - - public static final ErrorEval NAME_INVALID = ERROR_525; - - public static final ErrorEval VALUE_INVALID = ERROR_519; + public static final ErrorEval VALUE_INVALID = new ErrorEval(519); // Non std error codes diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/MultiplyEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/MultiplyEval.java index e55d53226a..bd4d0c539a 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/MultiplyEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/MultiplyEval.java @@ -22,6 +22,7 @@ public class MultiplyEval extends NumericOperationEval { | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED | ValueEvalToNumericXlator.STRING_IS_PARSED + | ValueEvalToNumericXlator.REF_STRING_IS_PARSED )); public MultiplyEval(Ptg ptg) { diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/NumberEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/NumberEval.java index 764c59f205..9ca0d74685 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/NumberEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/NumberEval.java @@ -13,6 +13,8 @@ import org.apache.poi.hssf.record.formula.Ptg; * */ public class NumberEval implements NumericValueEval, StringValueEval { + + public static final NumberEval ZERO = new NumberEval(0); private double value; private String stringValue; diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/PowerEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/PowerEval.java index 641cf10ae6..ef34d21f5f 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/PowerEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/PowerEval.java @@ -22,6 +22,7 @@ public class PowerEval extends NumericOperationEval { | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED | ValueEvalToNumericXlator.STRING_IS_PARSED + | ValueEvalToNumericXlator.REF_STRING_IS_PARSED )); public PowerEval(Ptg ptg) { diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/RelationalOperationEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/RelationalOperationEval.java index de5004d92d..b07f70879a 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/RelationalOperationEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/RelationalOperationEval.java @@ -38,7 +38,7 @@ public abstract class RelationalOperationEval implements OperationEval { switch (operands.length) { default: - retval.ee = ErrorEval.ERROR_520; + retval.ee = ErrorEval.VALUE_INVALID; break; case 2: internalDoEvaluate(operands, srcRow, srcCol, retval, 0); diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/StringEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/StringEval.java index f8b4cca00d..9f7869c9ad 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/StringEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/StringEval.java @@ -13,6 +13,8 @@ import org.apache.poi.hssf.record.formula.StringPtg; */ public class StringEval implements StringValueEval { + public static final StringEval EMPTY_INSTANCE = new StringEval(""); + private String value; public StringEval(Ptg ptg) { diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/SubtractEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/SubtractEval.java index 6b2c9899cf..8b8208db64 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/SubtractEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/SubtractEval.java @@ -22,6 +22,7 @@ public class SubtractEval extends NumericOperationEval { | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED | ValueEvalToNumericXlator.STRING_IS_PARSED + | ValueEvalToNumericXlator.REF_STRING_IS_PARSED )); public SubtractEval(Ptg ptg) { diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/UnaryMinusEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/UnaryMinusEval.java index 84eececceb..793290a04a 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/UnaryMinusEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/UnaryMinusEval.java @@ -21,6 +21,7 @@ public class UnaryMinusEval extends NumericOperationEval { | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED | ValueEvalToNumericXlator.STRING_IS_PARSED + | ValueEvalToNumericXlator.REF_STRING_IS_PARSED )); diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/UnaryPlusEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/UnaryPlusEval.java index 5b311661fd..556b3f8de8 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/UnaryPlusEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/UnaryPlusEval.java @@ -18,7 +18,7 @@ public class UnaryPlusEval implements OperationEval /*extends NumericOperationEv /* * COMMENT FOR COMMENTED CODE IN THIS FILE * - * The loser who programmed this in excel didnt care to + * In excel the programmer seems to not have cared to * think about how strings were handled in other numeric * operations when he/she was implementing this operation :P * @@ -27,10 +27,8 @@ public class UnaryPlusEval implements OperationEval /*extends NumericOperationEv * Q. If the formula -"hello" evaluates to #VALUE! in excel, what should * the formula +"hello" evaluate to? * - * A. +"hello" evaluates to "hello" + * A. +"hello" evaluates to "hello" (what the...?) * - * DO NOT remove the commented code (In memory of the excel - * programmer who implemented the UnaryPlus operation :) */ diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/ValueEvalToNumericXlator.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/ValueEvalToNumericXlator.java index fb089227e5..3111a42156 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/ValueEvalToNumericXlator.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/ValueEvalToNumericXlator.java @@ -10,25 +10,33 @@ package org.apache.poi.hssf.record.formula.eval; */ public class ValueEvalToNumericXlator { - public static final short STRING_IS_PARSED = 0x0001; - public static final short BOOL_IS_PARSED = 0x0002; + public static final int STRING_IS_PARSED = 0x0001; + public static final int BOOL_IS_PARSED = 0x0002; + public static final int BLANK_IS_PARSED = 0x0004; // => blanks are not ignored, converted to 0 - public static final short REF_STRING_IS_PARSED = 0x0004; - public static final short REF_BOOL_IS_PARSED = 0x0008; + public static final int REF_STRING_IS_PARSED = 0x0008; + public static final int REF_BOOL_IS_PARSED = 0x0010; + public static final int REF_BLANK_IS_PARSED = 0x0020; - public static final short EVALUATED_REF_STRING_IS_PARSED = 0x0010; - public static final short EVALUATED_REF_BOOL_IS_PARSED = 0x0020; + public static final int EVALUATED_REF_STRING_IS_PARSED = 0x0040; + public static final int EVALUATED_REF_BOOL_IS_PARSED = 0x0080; + public static final int EVALUATED_REF_BLANK_IS_PARSED = 0x0100; - public static final short STRING_TO_BOOL_IS_PARSED = 0x0040; - public static final short REF_STRING_TO_BOOL_IS_PARSED = 0x0080; + public static final int STRING_TO_BOOL_IS_PARSED = 0x0200; + public static final int REF_STRING_TO_BOOL_IS_PARSED = 0x0400; - public static final short STRING_IS_INVALID_VALUE = 0x0100; - public static final short REF_STRING_IS_INVALID_VALUE = 0x200; + public static final int STRING_IS_INVALID_VALUE = 0x0800; + public static final int REF_STRING_IS_INVALID_VALUE = 0x1000; - private final short flags; +// public static final int BOOL_IS_BLANK = 0x2000; +// public static final int REF_BOOL_IS_BLANK = 0x4000; +// public static final int STRING_IS_BLANK = 0x8000; +// public static final int REF_STRING_IS_BLANK = 0x10000; + private final int flags; - public ValueEvalToNumericXlator(short flags) { + + public ValueEvalToNumericXlator(int flags) { this.flags = flags; } @@ -52,23 +60,20 @@ public class ValueEvalToNumericXlator { } // booleval - else if (((flags | BOOL_IS_PARSED) > 0) && eval instanceof BoolEval) { - retval = (NumericValueEval) eval; + else if (eval instanceof BoolEval) { + retval = ((flags & BOOL_IS_PARSED) > 0) + ? (NumericValueEval) eval + : xlateBlankEval(BLANK_IS_PARSED); } // stringeval else if (eval instanceof StringEval) { - retval = handleStringEval((StringEval) eval); + retval = xlateStringEval((StringEval) eval); // TODO: recursive call needed } // refeval else if (eval instanceof RefEval) { - retval = handleRefEval((RefEval) eval); - } - - //blankeval - else if (eval instanceof BlankEval) { - retval = eval; + retval = xlateRefEval((RefEval) eval); } // erroreval @@ -76,40 +81,55 @@ public class ValueEvalToNumericXlator { retval = eval; } + else if (eval instanceof BlankEval) { + retval = xlateBlankEval(BLANK_IS_PARSED); + } + // probably AreaEval? then not acceptable. else { throw new RuntimeException("Invalid ValueEval type passed for conversion: " + eval.getClass()); } + return retval; } + /** + * no args are required since BlankEval has only one + * instance. If flag is set, a zero + * valued numbereval is returned, else BlankEval.INSTANCE + * is returned. + * @return + */ + private ValueEval xlateBlankEval(int flag) { + return ((flags & flag) > 0) + ? (ValueEval) NumberEval.ZERO + : BlankEval.INSTANCE; + } + /** * uses the relevant flags to decode the supplied RefVal * @param eval * @return */ - private ValueEval handleRefEval(RefEval reval) { + private ValueEval xlateRefEval(RefEval reval) { ValueEval retval = null; ValueEval eval = (ValueEval) reval.getInnerValueEval(); // most common case - least worries :) if (eval instanceof NumberEval) { - retval = (NumberEval) eval; // the cast is correct :) + retval = (NumberEval) eval; } // booleval - else if (((flags | REF_BOOL_IS_PARSED) > 0) && eval instanceof BoolEval) { - retval = (NumericValueEval) eval; + else if (eval instanceof BoolEval) { + retval = ((flags & REF_BOOL_IS_PARSED) > 0) + ? (ValueEval) eval + : BlankEval.INSTANCE; } // stringeval else if (eval instanceof StringEval) { - retval = handleRefStringEval((StringEval) eval); - } - - //blankeval - else if (eval instanceof BlankEval) { - retval = eval; + retval = xlateRefStringEval((StringEval) eval); } // erroreval @@ -117,10 +137,24 @@ public class ValueEvalToNumericXlator { retval = eval; } - // probably AreaEval or another RefEval? then not acceptable. - else { + // refeval + else if (eval instanceof RefEval) { + RefEval re = (RefEval) eval; + retval = xlateRefEval(re); + } + + else if (eval instanceof BlankEval) { + retval = xlateBlankEval(reval.isEvaluated() ? EVALUATED_REF_BLANK_IS_PARSED : REF_BLANK_IS_PARSED); + } + + // probably AreaEval ? then not acceptable. + else { throw new RuntimeException("Invalid ValueEval type passed for conversion: " + eval.getClass()); } + + + + return retval; } @@ -129,20 +163,29 @@ public class ValueEvalToNumericXlator { * @param eval * @return */ - private ValueEval handleStringEval(StringEval eval) { + private ValueEval xlateStringEval(StringEval eval) { ValueEval retval = null; - if ((flags | STRING_IS_PARSED) > 0) { - StringEval sve = (StringEval) eval; - String s = sve.getStringValue(); + if ((flags & STRING_IS_PARSED) > 0) { + String s = eval.getStringValue(); try { double d = Double.parseDouble(s); retval = new NumberEval(d); } - catch (Exception e) { retval = ErrorEval.VALUE_INVALID; } + catch (Exception e) { + if ((flags & STRING_TO_BOOL_IS_PARSED) > 0) { + try { + boolean b = Boolean.getBoolean(s); + retval = b ? BoolEval.TRUE : BoolEval.FALSE; + } + catch (Exception e2) { retval = ErrorEval.VALUE_INVALID; } + } + else { + retval = ErrorEval.VALUE_INVALID; + } + } } - else if ((flags | STRING_TO_BOOL_IS_PARSED) > 0) { - StringEval sve = (StringEval) eval; - String s = sve.getStringValue(); + else if ((flags & STRING_TO_BOOL_IS_PARSED) > 0) { + String s = eval.getStringValue(); try { boolean b = Boolean.getBoolean(s); retval = b ? BoolEval.TRUE : BoolEval.FALSE; @@ -151,13 +194,13 @@ public class ValueEvalToNumericXlator { } // strings are errors? - else if ((flags | STRING_IS_INVALID_VALUE) > 0) { + else if ((flags & STRING_IS_INVALID_VALUE) > 0) { retval = ErrorEval.VALUE_INVALID; } // ignore strings else { - retval = BlankEval.INSTANCE; + retval = xlateBlankEval(BLANK_IS_PARSED); } return retval; } @@ -167,18 +210,29 @@ public class ValueEvalToNumericXlator { * @param eval * @return */ - private ValueEval handleRefStringEval(StringEval eval) { + private ValueEval xlateRefStringEval(StringEval eval) { ValueEval retval = null; - if ((flags | REF_STRING_IS_PARSED) > 0) { + if ((flags & REF_STRING_IS_PARSED) > 0) { StringEval sve = (StringEval) eval; String s = sve.getStringValue(); try { double d = Double.parseDouble(s); retval = new NumberEval(d); } - catch (Exception e) { retval = ErrorEval.VALUE_INVALID; } + catch (Exception e) { + if ((flags & REF_STRING_TO_BOOL_IS_PARSED) > 0) { + try { + boolean b = Boolean.getBoolean(s); + retval = b ? BoolEval.TRUE : BoolEval.FALSE; + } + catch (Exception e2) { retval = ErrorEval.VALUE_INVALID; } + } + else { + retval = ErrorEval.VALUE_INVALID; + } + } } - else if ((flags | REF_STRING_TO_BOOL_IS_PARSED) > 0) { + else if ((flags & REF_STRING_TO_BOOL_IS_PARSED) > 0) { StringEval sve = (StringEval) eval; String s = sve.getStringValue(); try { @@ -189,11 +243,11 @@ public class ValueEvalToNumericXlator { } // strings are errors? - else if ((flags | REF_STRING_IS_INVALID_VALUE) > 0) { + else if ((flags & REF_STRING_IS_INVALID_VALUE) > 0) { retval = ErrorEval.VALUE_INVALID; } - // ignore strings + // strings are blanks else { retval = BlankEval.INSTANCE; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Abs.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Abs.java index 9f29615ae5..31960a9b92 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Abs.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Abs.java @@ -10,7 +10,6 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > @@ -18,19 +17,6 @@ import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; */ public class Abs extends NumericFunction { - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } - public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; @@ -54,7 +40,10 @@ public class Abs extends NumericFunction { } if (retval == null) { - retval = (Double.isNaN(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(Math.abs(d)); + d = Math.abs(d); + retval = (Double.isNaN(d)) + ? (ValueEval) ErrorEval.VALUE_INVALID + : new NumberEval(d); } return retval; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Acos.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Acos.java index eb8e69301a..dc6030ca9c 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Acos.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Acos.java @@ -10,33 +10,20 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * + * */ public class Acos extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 1: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -51,10 +38,12 @@ public class Acos extends NumericFunction { retval = ErrorEval.NUM_ERROR; } } - + if (retval == null) { d = Math.acos(d); - retval = (Double.isNaN(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d); + retval = (Double.isNaN(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); } return retval; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Acosh.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Acosh.java index 570e109325..1ff637071e 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Acosh.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Acosh.java @@ -9,38 +9,25 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * Support for hyperbolic trig functions was added as a part of - * Java distribution only in JDK1.5. This class uses custom + * Support for hyperbolic trig functions was added as a part of + * Java distribution only in JDK1.5. This class uses custom * naive implementation based on formulas at: * http://www.math2.org/math/trig/hyperbolics.htm * These formulas seem to agree with excel's implementation. - * + * */ public class Acosh extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 1: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -49,10 +36,12 @@ public class Acosh extends NumericFunction { d = ne.getNumberValue(); } } - + if (retval == null) { - d = Math.log(Math.sqrt(Math.pow(d, 2) - 1) + d); - retval = (Double.isNaN(d) || Double.isInfinite(d)) ? (ValueEval) ErrorEval.NUM_ERROR : new NumberEval(d); + d = MathX.acosh(d); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); } return retval; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Asin.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Asin.java index ebf169b93c..a4e005e91f 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Asin.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Asin.java @@ -10,33 +10,20 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * + * */ public class Asin extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 1: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -51,10 +38,12 @@ public class Asin extends NumericFunction { retval = ErrorEval.NUM_ERROR; } } - + if (retval == null) { d = Math.asin(d); - retval = (Double.isNaN(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d); + retval = (Double.isNaN(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); } return retval; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Asinh.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Asinh.java index b33f12c724..12c7bdc063 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Asinh.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Asinh.java @@ -10,38 +10,26 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * Support for hyperbolic trig functions was added as a part of - * Java distribution only in JDK1.5. This class uses custom + * Support for hyperbolic trig functions was added as a part of + * Java distribution only in JDK1.5. This class uses custom * naive implementation based on formulas at: * http://www.math2.org/math/trig/hyperbolics.htm * These formulas seem to agree with excel's implementation. - * + * */ public class Asinh extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } + public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 1: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -56,9 +44,9 @@ public class Asinh extends NumericFunction { retval = ErrorEval.NUM_ERROR; } } - + if (retval == null) { - d = Math.log(Math.sqrt(Math.pow(d, 2) + 1) + d); + d = MathX.asinh(d); retval = (Double.isNaN(d)) ? (ValueEval) ErrorEval.NUM_ERROR : new NumberEval(d); } return retval; diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Atan.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Atan.java index a156c0f2d6..6fcc9c3c28 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Atan.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Atan.java @@ -10,33 +10,20 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * + * */ public class Atan extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 1: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -51,10 +38,12 @@ public class Atan extends NumericFunction { retval = ErrorEval.NUM_ERROR; } } - + if (retval == null) { d = Math.atan(d); - retval = (Double.isNaN(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d); + retval = (Double.isNaN(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); } return retval; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Atan2.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Atan2.java index 89e6b09041..fa1afbf420 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Atan2.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Atan2.java @@ -10,34 +10,21 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * + * */ public class Atan2 extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d0 = 0; double d1 = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 2: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -51,7 +38,7 @@ public class Atan2 extends NumericFunction { else { retval = ErrorEval.NUM_ERROR; } - + if (retval == null) { ve = singleOperandEvaluate(operands[1], srcRow, srcCol); if (ve instanceof NumericValueEval) { @@ -66,10 +53,14 @@ public class Atan2 extends NumericFunction { } } } - + if (retval == null) { - double d = (d0 == d1 && d1 == 0) ? Double.NaN : Math.atan2(d1, d0); - retval = (Double.isNaN(d) || Double.isInfinite(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d); + double d = (d0 == d1 && d1 == 0) + ? Double.NaN + : Math.atan2(d1, d0); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); } return retval; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Atanh.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Atanh.java index 7049185414..a17a9aff50 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Atanh.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Atanh.java @@ -10,38 +10,25 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * Support for hyperbolic trig functions was added as a part of - * Java distribution only in JDK1.5. This class uses custom + * Support for hyperbolic trig functions was added as a part of + * Java distribution only in JDK1.5. This class uses custom * naive implementation based on formulas at: * http://www.math2.org/math/trig/hyperbolics.htm * These formulas seem to agree with excel's implementation. - * + * */ public class Atanh extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 1: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -56,9 +43,9 @@ public class Atanh extends NumericFunction { retval = ErrorEval.NUM_ERROR; } } - + if (retval == null) { - d = Math.log((1 + d)/(1 - d)) / 2; + d = MathX.atanh(d); retval = (Double.isNaN(d) || Double.isInfinite(d)) ? (ValueEval) ErrorEval.NUM_ERROR : new NumberEval(d); } return retval; diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Avedev.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Avedev.java index 850e40e3fd..98e5bd70b8 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Avedev.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Avedev.java @@ -4,10 +4,58 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Avedev extends DefaultFunctionImpl { +public class Avedev extends MultiOperandNumericFunction { + + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) (0 + // ValueEvalToNumericXlator.BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + | ValueEvalToNumericXlator.EVALUATED_REF_BLANK_IS_PARSED + )); + + /** + * this is the default impl for the factory method getXlator + * of the super class NumericFunction. Subclasses can override this method + * if they desire to return a different ValueEvalToNumericXlator instance + * than the default. + */ + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } + + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[] values = getNumberArray(operands, srcCellRow, srcCellCol); + if (values == null) { + retval = ErrorEval.VALUE_INVALID; + } + else { + double d = StatsLib.avedev(values); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Average.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Average.java index 90accd5cc4..879ba78296 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Average.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Average.java @@ -4,10 +4,58 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Average extends DefaultFunctionImpl { +public class Average extends MultiOperandNumericFunction { + + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) (0 + // ValueEvalToNumericXlator.BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + | ValueEvalToNumericXlator.EVALUATED_REF_BLANK_IS_PARSED + )); + + /** + * this is the default impl for the factory method getXlator + * of the super class NumericFunction. Subclasses can override this method + * if they desire to return a different ValueEvalToNumericXlator instance + * than the default. + */ + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } + + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[] values = getNumberArray(operands, srcCellRow, srcCellCol); + if (values == null) { + retval = ErrorEval.VALUE_INVALID; + } + else { + double d = MathX.average(values); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Averagea.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Averagea.java index 719b1b6689..d87194ed1b 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Averagea.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Averagea.java @@ -4,10 +4,10 @@ */ package org.apache.poi.hssf.record.formula.functions; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ public class Averagea extends DefaultFunctionImpl { - } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Ceiling.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Ceiling.java index ee73137854..64ba612362 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Ceiling.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Ceiling.java @@ -1,14 +1,66 @@ /* - * Created on May 6, 2005 + * Created on May 15, 2005 * */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; /** - * @author - * + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + * */ -public class Ceiling extends DefaultFunctionImpl { - +public class Ceiling extends NumericFunction { + + public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { + double d0 = 0; + double d1 = 0; + ValueEval retval = null; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 2: + ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d0 = ne.getNumberValue(); + } + else if (ve instanceof BlankEval) { + // do nothing + } + else { + retval = ErrorEval.NUM_ERROR; + } + + if (retval == null) { + ve = singleOperandEvaluate(operands[1], srcRow, srcCol); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d1 = ne.getNumberValue(); + } + else if (ve instanceof BlankEval) { + // do nothing + } + else { + retval = ErrorEval.NUM_ERROR; + } + } + } + + if (retval == null) { + double d = MathX.ceiling(d0, d1); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + return retval; + } + } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Column.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Column.java index fa04a3ce0b..0bf4b7279d 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Column.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Column.java @@ -4,10 +4,50 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.AreaEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.RefEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** * @author * */ public class Column extends DefaultFunctionImpl { + public Eval evaluate(Eval[] evals, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + int cnum = -1; + + switch (evals.length) { + default: + retval = ErrorEval.VALUE_INVALID; + case 1: + if (evals[0] instanceof AreaEval) { + AreaEval ae = (AreaEval) evals[0]; + cnum = ae.getFirstColumn(); + } + else if (evals[0] instanceof RefEval) { + RefEval re = (RefEval) evals[0]; + cnum = re.getColumn(); + } + else { // anything else is not valid argument + retval = ErrorEval.VALUE_INVALID; + } + break; + case 0: + cnum = srcCellCol; + } + + if (retval == null) { + retval = (cnum >= 0) + ? new NumberEval(cnum + 1) // +1 since excel colnums are 1 based + : (ValueEval) ErrorEval.VALUE_INVALID; + } + + return retval; + } + } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Combin.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Combin.java index 1360d9a66f..82e951090a 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Combin.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Combin.java @@ -4,10 +4,68 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Combin extends DefaultFunctionImpl { +public class Combin extends NumericFunction { + + public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { + double d0 = 0; + double d1 = 0; + ValueEval retval = null; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 2: + ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d0 = ne.getNumberValue(); + } + else if (ve instanceof BlankEval) { + // do nothing + } + else { + retval = ErrorEval.NUM_ERROR; + } + + if (retval == null) { + ve = singleOperandEvaluate(operands[1], srcRow, srcCol); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d1 = ne.getNumberValue(); + } + else if (ve instanceof BlankEval) { + // do nothing + } + else { + retval = ErrorEval.NUM_ERROR; + } + } + } + + if (retval == null) { + if (d0 > Integer.MAX_VALUE || d1 > Integer.MAX_VALUE) { + retval = ErrorEval.NUM_ERROR; + } + else { + double d = MathX.nChooseK((int) d0, (int) d1); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Concatenate.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Concatenate.java index ed920f583c..beaa32d4ec 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Concatenate.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Concatenate.java @@ -4,10 +4,41 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.StringValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Concatenate extends DefaultFunctionImpl { +public class Concatenate extends TextFunction { + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + StringBuffer sb = new StringBuffer(); + + for (int i=0, iSize=operands.length; i= 0) { + d = MathX.factorial((int) d); + retval = (Double.isNaN(d)) + ? (ValueEval) ErrorEval.VALUE_INVALID + : (Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + else { + retval = ErrorEval.NUM_ERROR; + } + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Floor.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Floor.java index 17b9671ab4..9ce1fff730 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Floor.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Floor.java @@ -4,10 +4,63 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Floor extends DefaultFunctionImpl { +public class Floor extends NumericFunction { + + public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { + double d0 = 0; + double d1 = 0; + ValueEval retval = null; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 2: + ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d0 = ne.getNumberValue(); + } + else if (ve instanceof BlankEval) { + // do nothing + } + else { + retval = ErrorEval.NUM_ERROR; + } + + if (retval == null) { + ve = singleOperandEvaluate(operands[1], srcRow, srcCol); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d1 = ne.getNumberValue(); + } + else if (ve instanceof BlankEval) { + // do nothing + } + else { + retval = ErrorEval.NUM_ERROR; + } + } + } + + if (retval == null) { + double d = MathX.floor(d0, d1); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Int.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Int.java index fb60fc0294..391139ded8 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Int.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Int.java @@ -10,33 +10,20 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * + * */ public class Int extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 1: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -51,12 +38,14 @@ public class Int extends NumericFunction { retval = ErrorEval.NUM_ERROR; } } - + if (retval == null) { if (d < 0) { d = Math.round(d-0.5); } - retval = (Double.isNaN(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval((long) d); + retval = (Double.isNaN(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval((long) d); } return retval; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/IsError.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/IsError.java index e3d24e088a..60da1e61ee 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/IsError.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/IsError.java @@ -4,10 +4,77 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.AreaEval; +import org.apache.poi.hssf.record.formula.eval.BoolEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.RefEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class IsError extends DefaultFunctionImpl { +public class IsError implements Function { + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + boolean b = false; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 1: + if (operands[0] instanceof ErrorEval) { + b = true; + } + else if (operands[0] instanceof AreaEval) { + AreaEval ae = (AreaEval) operands[0]; + if (ae.contains(srcCellRow, srcCellCol)) { // circular ref! + retval = ErrorEval.CIRCULAR_REF_ERROR; + } + else if (ae.isRow()) { + if (ae.containsColumn(srcCellCol)) { + ValueEval ve = ae.getValueAt(ae.getFirstRow(), srcCellCol); + if (ve instanceof RefEval) + b = ((RefEval) ve).getInnerValueEval() instanceof ErrorEval; + else + b = (ve instanceof ErrorEval); + } + else { + b = true; + } + } + else if (ae.isColumn()) { + if (ae.containsRow(srcCellRow)) { + ValueEval ve = ae.getValueAt(srcCellRow, ae.getFirstColumn()); + if (ve instanceof RefEval) + b = ((RefEval) ve).getInnerValueEval() instanceof ErrorEval; + else + b = (ve instanceof ErrorEval); + } + else { + b = true; + } + } + else { + b = true; + } + } + else if (operands[0] instanceof RefEval) { + b = ((RefEval) operands[0]).getInnerValueEval() instanceof ErrorEval; + } + else { + b = false; + } + } + + if (retval == null) { + retval = b + ? BoolEval.TRUE + : BoolEval.FALSE; + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Isblank.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Isblank.java index 7d47905a15..53973d8db1 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Isblank.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Isblank.java @@ -4,10 +4,73 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.AreaEval; +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.BoolEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.RefEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Isblank extends DefaultFunctionImpl { +public class Isblank implements Function { + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + boolean b = false; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 1: + if (operands[0] instanceof BlankEval) { + b = true; + } + else if (operands[0] instanceof AreaEval) { + AreaEval ae = (AreaEval) operands[0]; + if (ae.contains(srcCellRow, srcCellCol)) { // circular ref! + retval = ErrorEval.CIRCULAR_REF_ERROR; + } + else if (ae.isRow()) { + if (ae.containsColumn(srcCellCol)) { + ValueEval ve = ae.getValueAt(ae.getFirstRow(), srcCellCol); + b = (ve instanceof BlankEval); + } + else { + b = false; + } + } + else if (ae.isColumn()) { + if (ae.containsRow(srcCellRow)) { + ValueEval ve = ae.getValueAt(srcCellRow, ae.getFirstColumn()); + b = (ve instanceof BlankEval); + } + else { + b = false; + } + } + else { + b = false; + } + } + else if (operands[0] instanceof RefEval) { + RefEval re = (RefEval) operands[0]; + b = (!re.isEvaluated()) && re.getInnerValueEval() instanceof BlankEval; + } + else { + b = false; + } + } + + if (retval == null) { + retval = b + ? BoolEval.TRUE + : BoolEval.FALSE; + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Large.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Large.java index 79c9e3caa8..355bd71843 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Large.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Large.java @@ -4,10 +4,62 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Large extends DefaultFunctionImpl { +public class Large extends MultiOperandNumericFunction { + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) (0 + | ValueEvalToNumericXlator.BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.EVALUATED_REF_BLANK_IS_PARSED + //| ValueEvalToNumericXlator.REF_BLANK_IS_PARSED + //| ValueEvalToNumericXlator.BLANK_IS_PARSED + )); + + /** + * this is the default impl for the factory method getXlator + * of the super class NumericFunction. Subclasses can override this method + * if they desire to return a different ValueEvalToNumericXlator instance + * than the default. + */ + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } + + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[] ops = getNumberArray(operands, srcCellRow, srcCellCol); + if (ops == null || ops.length < 2) { + retval = ErrorEval.VALUE_INVALID; + } + else { + double[] values = new double[ops.length-1]; + int k = (int) ops[ops.length-1]; + System.arraycopy(ops, 0, values, 0, values.length); + double d = StatsLib.kthLargest(values, k); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Len.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Len.java index a9ac39874b..c72146d828 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Len.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Len.java @@ -4,10 +4,120 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.AreaEval; +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.RefEval; +import org.apache.poi.hssf.record.formula.eval.StringValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Len extends DefaultFunctionImpl { +public class Len extends TextFunction { + + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + String s = null; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 1: + ValueEval ve = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol); + if (ve instanceof StringValueEval) { + StringValueEval sve = (StringValueEval) ve; + s = sve.getStringValue(); + } + else if (ve instanceof RefEval) { + RefEval re = (RefEval) ve; + ValueEval ive = re.getInnerValueEval(); + if (ive instanceof BlankEval) { + s = re.isEvaluated() ? "0" : null; + } + else if (ive instanceof StringValueEval) { + s = ((StringValueEval) ive).getStringValue(); + } + else if (ive instanceof BlankEval) {} + else { + retval = ErrorEval.VALUE_INVALID; + } + } + else if (ve instanceof BlankEval) {} + else { + retval = ErrorEval.VALUE_INVALID; + break; + } + } + + if (retval == null) { + s = (s == null) ? EMPTY_STRING : s; + retval = new NumberEval(s.length()); + } + + return retval; + } + + + protected ValueEval singleOperandEvaluate(Eval eval, int srcRow, short srcCol) { + ValueEval retval; + if (eval instanceof AreaEval) { + AreaEval ae = (AreaEval) eval; + if (ae.contains(srcRow, srcCol)) { // circular ref! + retval = ErrorEval.CIRCULAR_REF_ERROR; + } + else if (ae.isRow()) { + if (ae.containsColumn(srcCol)) { + ValueEval ve = ae.getValueAt(ae.getFirstRow(), srcCol); + retval = attemptXlateToText(ve); + } + else { + retval = ErrorEval.VALUE_INVALID; + } + } + else if (ae.isColumn()) { + if (ae.containsRow(srcRow)) { + ValueEval ve = ae.getValueAt(srcRow, ae.getFirstColumn()); + retval = attemptXlateToText(ve); + } + else { + retval = ErrorEval.VALUE_INVALID; + } + } + else { + retval = ErrorEval.VALUE_INVALID; + } + } + else { + retval = attemptXlateToText((ValueEval) eval); + } + return retval; + } + + /** + * converts from Different ValueEval types to StringEval. + * Note: AreaEvals are not handled, if arg is an AreaEval, + * the returned value is ErrorEval.VALUE_INVALID + * @param ve + * @return + */ + protected ValueEval attemptXlateToText(ValueEval ve) { + ValueEval retval; + if (ve instanceof StringValueEval || ve instanceof RefEval) { + retval = ve; + } + else if (ve instanceof BlankEval) { + retval = ve; + } + else { + retval = ErrorEval.VALUE_INVALID; + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Ln.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Ln.java index 5e80259b9a..fe3a6a2251 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Ln.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Ln.java @@ -14,29 +14,17 @@ import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * + * */ public class Ln extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 1: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -51,7 +39,7 @@ public class Ln extends NumericFunction { retval = ErrorEval.NUM_ERROR; } } - + if (retval == null) { d = Math.log(d); retval = (Double.isNaN(d) || Double.isInfinite(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d); diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Log.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Log.java index 044557b351..3732f63db3 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Log.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Log.java @@ -17,32 +17,20 @@ import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; * Log: LOG(number,[base]) */ public class Log extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - private static final double DEFAULT_BASE = 10; - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } + private static final double DEFAULT_BASE = 10; public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; double base = DEFAULT_BASE; double num = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; - case 2: // second arg is base + case 2: // second arg is base ValueEval ve = singleOperandEvaluate(operands[1], srcRow, srcCol); if (ve instanceof NumericValueEval) { NumericValueEval ne = (NumericValueEval) ve; @@ -54,7 +42,7 @@ public class Log extends NumericFunction { else { retval = ErrorEval.NUM_ERROR; } - + case 1: // first arg is number if (retval == null) { ValueEval vev = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -70,9 +58,9 @@ public class Log extends NumericFunction { } } } - + if (retval == null) { - d = (base == E) + d = (base == E) ? Math.log(num) : Math.log(num) / Math.log(base); retval = (Double.isNaN(d) || Double.isInfinite(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d); diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Log10.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Log10.java index ee8261cd54..d884eee432 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Log10.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Log10.java @@ -10,35 +10,21 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * + * */ public class Log10 extends NumericFunction { private static final double LOG_10_TO_BASE_e = Math.log(10); - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } - public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 1: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -53,10 +39,12 @@ public class Log10 extends NumericFunction { retval = ErrorEval.NUM_ERROR; } } - + if (retval == null) { d = Math.log(d) / LOG_10_TO_BASE_e; - retval = (Double.isNaN(d) || Double.isInfinite(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); } return retval; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Lower.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Lower.java index e5b6f9dc6c..75aef4cdf3 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Lower.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Lower.java @@ -4,10 +4,46 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.StringValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Lower extends DefaultFunctionImpl { +public class Lower extends TextFunction { + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + String s = null; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 1: + ValueEval ve = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol); + if (ve instanceof StringValueEval) { + StringValueEval sve = (StringValueEval) ve; + s = sve.getStringValue(); + } + else if (ve instanceof BlankEval) {} + else { + retval = ErrorEval.VALUE_INVALID; + break; + } + } + + if (retval == null) { + s = (s == null) ? EMPTY_STRING : s; + retval = new StringEval(s.toLowerCase()); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Max.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Max.java index 521bc15b4e..efe4b5cbb1 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Max.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Max.java @@ -4,10 +4,49 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Max extends DefaultFunctionImpl { +public class Max extends MultiOperandNumericFunction { + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) ( + ValueEvalToNumericXlator.BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + )); + + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[] values = getNumberArray(operands, srcCellRow, srcCellCol); + if (values == null) { + retval = ErrorEval.VALUE_INVALID; + } + else { + double d = values.length > 0 ? MathX.max(values) : 0; + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Maxa.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Maxa.java index b9605ac3b6..2494c3bcc6 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Maxa.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Maxa.java @@ -4,10 +4,51 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Maxa extends DefaultFunctionImpl { +public class Maxa extends MultiOperandNumericFunction { + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) ( + ValueEvalToNumericXlator.BOOL_IS_PARSED + | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + | ValueEvalToNumericXlator.BLANK_IS_PARSED + | ValueEvalToNumericXlator.REF_BLANK_IS_PARSED + )); + + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[] values = getNumberArray(operands, srcCellRow, srcCellCol); + if (values == null) { + retval = ErrorEval.VALUE_INVALID; + } + else { + double d = values.length > 0 ? MathX.max(values) : 0; + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Median.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Median.java index 917819ca0a..9a7c175e99 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Median.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Median.java @@ -4,10 +4,58 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Median extends DefaultFunctionImpl { +public class Median extends MultiOperandNumericFunction { + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) (0 + | ValueEvalToNumericXlator.BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.EVALUATED_REF_BLANK_IS_PARSED + //| ValueEvalToNumericXlator.REF_BLANK_IS_PARSED + //| ValueEvalToNumericXlator.BLANK_IS_PARSED + )); + + /** + * this is the default impl for the factory method getXlator + * of the super class NumericFunction. Subclasses can override this method + * if they desire to return a different ValueEvalToNumericXlator instance + * than the default. + */ + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[] values = getNumberArray(operands, srcCellRow, srcCellCol); + if (values == null) { + retval = ErrorEval.VALUE_INVALID; + } + else { + double d = StatsLib.median(values); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Min.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Min.java index ee3355f7be..7fb00f14b3 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Min.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Min.java @@ -4,10 +4,49 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Min extends DefaultFunctionImpl { +public class Min extends MultiOperandNumericFunction { + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) ( + ValueEvalToNumericXlator.BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + )); + + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[] values = getNumberArray(operands, srcCellRow, srcCellCol); + if (values == null) { + retval = ErrorEval.VALUE_INVALID; + } + else { + double d = values.length > 0 ? MathX.min(values) : 0; + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mina.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mina.java index e75ab4d147..8be4320fe9 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mina.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mina.java @@ -4,10 +4,51 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Mina extends DefaultFunctionImpl { +public class Mina extends MultiOperandNumericFunction { + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) ( + ValueEvalToNumericXlator.BOOL_IS_PARSED + | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + | ValueEvalToNumericXlator.REF_BLANK_IS_PARSED + | ValueEvalToNumericXlator.BLANK_IS_PARSED + )); + + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[] values = getNumberArray(operands, srcCellRow, srcCellCol); + if (values == null) { + retval = ErrorEval.VALUE_INVALID; + } + else { + double d = values.length > 0 ? MathX.min(values) : 0; + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mod.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mod.java index 696dabba49..d272c535d1 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mod.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mod.java @@ -4,10 +4,68 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Mod extends DefaultFunctionImpl { +public class Mod extends NumericFunction { + + public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { + double d0 = 0; + double d1 = 0; + ValueEval retval = null; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 2: + ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d0 = ne.getNumberValue(); + } + else if (ve instanceof BlankEval) { + // do nothing + } + else { + retval = ErrorEval.NUM_ERROR; + } + + if (retval == null) { + ve = singleOperandEvaluate(operands[1], srcRow, srcCol); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d1 = ne.getNumberValue(); + } + else if (ve instanceof BlankEval) { + // do nothing + } + else { + retval = ErrorEval.NUM_ERROR; + } + } + } + + if (retval == null) { + if (d1 == 0) { + retval = ErrorEval.DIV_ZERO; + } + else { + double d = MathX.mod(d0, d1); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mode.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mode.java index c2e3b388bd..ae605881fd 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mode.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mode.java @@ -4,10 +4,59 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Mode extends DefaultFunctionImpl { +public class Mode extends MultiOperandNumericFunction { + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) (0 + //| ValueEvalToNumericXlator.BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.STRING_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.EVALUATED_REF_BLANK_IS_PARSED + //| ValueEvalToNumericXlator.REF_BLANK_IS_PARSED + //| ValueEvalToNumericXlator.BLANK_IS_PARSED + )); + + /** + * this is the default impl for the factory method getXlator + * of the super class NumericFunction. Subclasses can override this method + * if they desire to return a different ValueEvalToNumericXlator instance + * than the default. + */ + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } + + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[] values = getNumberArray(operands, srcCellRow, srcCellCol); + if (values == null) { + retval = ErrorEval.VALUE_INVALID; + } + else { + double d = StatsLib.mode(values); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/NumericFunction.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/NumericFunction.java index 24c4415b12..05b7346c19 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/NumericFunction.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/NumericFunction.java @@ -18,8 +18,32 @@ public abstract class NumericFunction implements Function { protected static final double E = Math.E; protected static final double PI = Math.PI; + + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) ( + ValueEvalToNumericXlator.BOOL_IS_PARSED + | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_PARSED + | ValueEvalToNumericXlator.REF_STRING_IS_PARSED + | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + )); + + private static final int DEFAULT_MAX_NUM_OPERANDS = 30; - protected abstract ValueEvalToNumericXlator getXlator(); + /** + * this is the default impl of the factory(ish) method getXlator. + * Subclasses can override this method + * if they desire to return a different ValueEvalToNumericXlator instance + * than the default. + */ + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } protected ValueEval singleOperandEvaluate(Eval eval, int srcRow, short srcCol) { ValueEval retval; diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Odd.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Odd.java index 3e35d4c2a9..be1ecb5efd 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Odd.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Odd.java @@ -10,7 +10,6 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > @@ -18,19 +17,6 @@ import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; */ public class Odd extends NumericFunction { - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } - public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Power.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Power.java index 6721fc3e20..b29ec03282 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Power.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Power.java @@ -10,27 +10,13 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ public class Power extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } - + public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d0 = 0; double d1 = 0; diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Product.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Product.java index f6d64268bf..539304641b 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Product.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Product.java @@ -4,10 +4,49 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Product extends DefaultFunctionImpl { +public class Product extends MultiOperandNumericFunction { + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) ( + ValueEvalToNumericXlator.BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + )); + + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[] values = getNumberArray(operands, srcCellRow, srcCellCol); + if (values == null) { + retval = ErrorEval.VALUE_INVALID; + } + else { + double d = MathX.product(values); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Radians.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Radians.java index 3df708b455..f7c187ab60 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Radians.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Radians.java @@ -10,7 +10,6 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > @@ -18,19 +17,6 @@ import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; */ public class Radians extends NumericFunction { - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } - public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Round.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Round.java index 93031f33d2..965cb2a10a 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Round.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Round.java @@ -4,10 +4,68 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** * @author * */ -public class Round extends DefaultFunctionImpl { +public class Round extends NumericFunction { + + public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { + double d0 = 0; + double d1 = 0; + ValueEval retval = null; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 2: + ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d0 = ne.getNumberValue(); + } + else if (ve instanceof BlankEval) { + // do nothing + } + else { + retval = ErrorEval.NUM_ERROR; + } + + if (retval == null) { + ve = singleOperandEvaluate(operands[1], srcRow, srcCol); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d1 = ne.getNumberValue(); + } + else if (ve instanceof BlankEval) { + // do nothing + } + else { + retval = ErrorEval.NUM_ERROR; + } + } + } + if (retval == null) { + double d; + if (d0 > Integer.MAX_VALUE) { + d = (Double.isNaN(d0) || Double.isInfinite(d0)) + ? Double.NaN + : 0; + } + else { + d = MathX.round(d0, (int) d1); + } + retval = (Double.isNaN(d) || Double.isInfinite(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d); + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Rounddown.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Rounddown.java index 0b789d172a..0daff4cc22 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Rounddown.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Rounddown.java @@ -4,10 +4,68 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** * @author * */ -public class Rounddown extends DefaultFunctionImpl { +public class Rounddown extends NumericFunction { + + public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { + double d0 = 0; + double d1 = 0; + ValueEval retval = null; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 2: + ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d0 = ne.getNumberValue(); + } + else if (ve instanceof BlankEval) { + // do nothing + } + else { + retval = ErrorEval.NUM_ERROR; + } + + if (retval == null) { + ve = singleOperandEvaluate(operands[1], srcRow, srcCol); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d1 = ne.getNumberValue(); + } + else if (ve instanceof BlankEval) { + // do nothing + } + else { + retval = ErrorEval.NUM_ERROR; + } + } + } + if (retval == null) { + double d; + if (d0 > Integer.MAX_VALUE) { + d = (Double.isInfinite(d0)) + ? Double.NaN + : 0; + } + else { + d = MathX.roundDown(d0, (int) d1); + } + retval = (Double.isNaN(d) || Double.isInfinite(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d); + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Roundup.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Roundup.java index b374be7c94..e46ac44af7 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Roundup.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Roundup.java @@ -4,10 +4,70 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** * @author * */ -public class Roundup extends DefaultFunctionImpl { +public class Roundup extends NumericFunction { + + public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { + double d0 = 0; + double d1 = 0; + ValueEval retval = null; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 2: + ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d0 = ne.getNumberValue(); + } + else if (ve instanceof BlankEval) { + // do nothing + } + else { + retval = ErrorEval.NUM_ERROR; + } + + if (retval == null) { + ve = singleOperandEvaluate(operands[1], srcRow, srcCol); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d1 = ne.getNumberValue(); + } + else if (ve instanceof BlankEval) { + // do nothing + } + else { + retval = ErrorEval.NUM_ERROR; + } + } + } + if (retval == null) { + double d; + if (d0 > Integer.MAX_VALUE) { + d = (Double.isNaN(d0)) + ? Double.NaN + : 0; + } + else { + d = MathX.roundUp(d0, (int) d1); + } + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Row.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Row.java index 1f0496f794..81bb4b1cd6 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Row.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Row.java @@ -4,10 +4,50 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.AreaEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.RefEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** * @author * */ -public class Row extends DefaultFunctionImpl { +public class Row implements Function { + public Eval evaluate(Eval[] evals, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + int rnum = -1; + + switch (evals.length) { + default: + retval = ErrorEval.VALUE_INVALID; + case 1: + if (evals[0] instanceof AreaEval) { + AreaEval ae = (AreaEval) evals[0]; + rnum = ae.getFirstRow(); + } + else if (evals[0] instanceof RefEval) { + RefEval re = (RefEval) evals[0]; + rnum = re.getRow(); + } + else { // anything else is not valid argument + retval = ErrorEval.VALUE_INVALID; + } + break; + case 0: + rnum = srcCellRow; + } + + if (retval == null) { + retval = (rnum >= 0) + ? new NumberEval(rnum + 1) // +1 since excel rownums are 1 based + : (ValueEval) ErrorEval.VALUE_INVALID; + } + + return retval; + } + } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sign.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sign.java index 3894bee5a4..8f7c45e609 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sign.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sign.java @@ -10,7 +10,6 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author @@ -18,19 +17,6 @@ import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; */ public class Sign extends NumericFunction { - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } - public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; @@ -56,11 +42,7 @@ public class Sign extends NumericFunction { if (retval == null) { retval = (Double.isNaN(d) || Double.isInfinite(d)) ? (ValueEval) ErrorEval.VALUE_INVALID - : (d == 0) - ? new NumberEval(0) - : (d < 0) - ? new NumberEval(-1) - : new NumberEval(1); + : new NumberEval(MathX.sign(d)); } return retval; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sin.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sin.java index 8d36bcb0dd..ab7dbda6a0 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sin.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sin.java @@ -10,33 +10,20 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * + * */ public class Sin extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 1: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -51,10 +38,12 @@ public class Sin extends NumericFunction { retval = ErrorEval.NUM_ERROR; } } - + if (retval == null) { d = Math.sin(d); - retval = (Double.isNaN(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d); + retval = (Double.isNaN(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); } return retval; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sinh.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sinh.java index 5624bf2f59..b9bc61ecae 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sinh.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sinh.java @@ -10,33 +10,20 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * + * */ public class Sinh extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 1: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -51,12 +38,12 @@ public class Sinh extends NumericFunction { retval = ErrorEval.NUM_ERROR; } } - + if (retval == null) { - double ePowX = Math.pow(E, d); - double ePowNegX = Math.pow(E, -d); - d = (ePowX - ePowNegX) / 2; - retval = (Double.isNaN(d) || Double.isInfinite(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d); + d = MathX.sinh(d); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); } return retval; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Small.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Small.java index 667ab11882..338750c02f 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Small.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Small.java @@ -4,10 +4,62 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Small extends DefaultFunctionImpl { +public class Small extends MultiOperandNumericFunction { + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) (0 + | ValueEvalToNumericXlator.BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.EVALUATED_REF_BLANK_IS_PARSED + //| ValueEvalToNumericXlator.REF_BLANK_IS_PARSED + //| ValueEvalToNumericXlator.BLANK_IS_PARSED + )); + + /** + * this is the default impl for the factory method getXlator + * of the super class NumericFunction. Subclasses can override this method + * if they desire to return a different ValueEvalToNumericXlator instance + * than the default. + */ + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } + + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[] ops = getNumberArray(operands, srcCellRow, srcCellCol); + if (ops == null || ops.length < 2) { + retval = ErrorEval.VALUE_INVALID; + } + else { + double[] values = new double[ops.length-1]; + int k = (int) ops[ops.length-1]; + System.arraycopy(ops, 0, values, 0, values.length); + double d = StatsLib.kthSmallest(values, k); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sqrt.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sqrt.java index fd6b76bf51..d990e55744 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sqrt.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sqrt.java @@ -10,33 +10,20 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * + * */ public class Sqrt extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 1: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -51,10 +38,12 @@ public class Sqrt extends NumericFunction { retval = ErrorEval.NUM_ERROR; } } - + if (retval == null) { d = Math.sqrt(d); - retval = (Double.isNaN(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d); + retval = (Double.isNaN(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); } return retval; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Stdev.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Stdev.java index 27559bc90f..fdb4b75f47 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Stdev.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Stdev.java @@ -4,10 +4,58 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Stdev extends DefaultFunctionImpl { +public class Stdev extends MultiOperandNumericFunction { + + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) (0 + // ValueEvalToNumericXlator.BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + | ValueEvalToNumericXlator.EVALUATED_REF_BLANK_IS_PARSED + )); + + /** + * this is the default impl for the factory method getXlator + * of the super class NumericFunction. Subclasses can override this method + * if they desire to return a different ValueEvalToNumericXlator instance + * than the default. + */ + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } + + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[] values = getNumberArray(operands, srcCellRow, srcCellCol); + if (values == null) { + retval = ErrorEval.VALUE_INVALID; + } + else { + double d = StatsLib.stdev(values); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sum.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sum.java index 7b09653195..e4003087d6 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sum.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sum.java @@ -4,10 +4,49 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Sum extends DefaultFunctionImpl { +public class Sum extends MultiOperandNumericFunction { + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) ( + ValueEvalToNumericXlator.BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + | ValueEvalToNumericXlator.STRING_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + )); + + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[] values = getNumberArray(operands, srcCellRow, srcCellCol); + if (values == null) { + retval = ErrorEval.VALUE_INVALID; + } + else { + double d = values.length > 0 ? MathX.sum(values) : 0; + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumproduct.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumproduct.java index 8ef361de31..e794b17482 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumproduct.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumproduct.java @@ -4,10 +4,10 @@ */ package org.apache.poi.hssf.record.formula.functions; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ public class Sumproduct extends DefaultFunctionImpl { - } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumsq.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumsq.java index 2f13693bc4..bf0dd80a49 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumsq.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumsq.java @@ -4,10 +4,51 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Sumsq extends DefaultFunctionImpl { +public class Sumsq extends MultiOperandNumericFunction { + private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = + new ValueEvalToNumericXlator((short) ( + // ValueEvalToNumericXlator.BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.STRING_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED + //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED + //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE + //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE + ValueEvalToNumericXlator.REF_BLANK_IS_PARSED + | ValueEvalToNumericXlator.BLANK_IS_PARSED + )); + + protected ValueEvalToNumericXlator getXlator() { + return DEFAULT_NUM_XLATOR; + } + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[] values = getNumberArray(operands, srcCellRow, srcCellCol); + if (values == null) { + retval = ErrorEval.VALUE_INVALID; + } + else { + double d = MathX.sumsq(values); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumx2my2.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumx2my2.java index 4a0267e889..98e9447f8d 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumx2my2.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumx2my2.java @@ -4,10 +4,44 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Sumx2my2 extends DefaultFunctionImpl { +public class Sumx2my2 extends XYNumericFunction { + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[][] values = null; + + int checkLen = 0; // check to see that all array lengths are equal + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 2: + values = getValues(operands, srcCellRow, srcCellCol); + if (values==null + || values[X] == null || values[Y] == null + || values[X].length == 0 || values[Y].length == 0 + || values[X].length != values[Y].length) { + retval = ErrorEval.VALUE_INVALID; + } + } + + if (retval == null) { + double d = MathX.sumx2my2(values[X], values[Y]); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumx2py2.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumx2py2.java index 5535612c77..da8771038b 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumx2py2.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumx2py2.java @@ -4,10 +4,44 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Sumx2py2 extends DefaultFunctionImpl { +public class Sumx2py2 extends XYNumericFunction { + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[][] values = null; + + int checkLen = 0; // check to see that all array lengths are equal + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 2: + values = getValues(operands, srcCellRow, srcCellCol); + if (values==null + || values[X] == null || values[Y] == null + || values[X].length == 0 || values[Y].length == 0 + || values[X].length != values[Y].length) { + retval = ErrorEval.VALUE_INVALID; + } + } + + if (retval == null) { + double d = MathX.sumx2py2(values[X], values[Y]); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumxmy2.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumxmy2.java index 60aed2ebb5..1998481ebf 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumxmy2.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sumxmy2.java @@ -4,10 +4,44 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Sumxmy2 extends DefaultFunctionImpl { +public class Sumxmy2 extends XYNumericFunction { + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + double[][] values = null; + + int checkLen = 0; // check to see that all array lengths are equal + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 2: + values = getValues(operands, srcCellRow, srcCellCol); + if (values==null + || values[X] == null || values[Y] == null + || values[X].length == 0 || values[Y].length == 0 + || values[X].length != values[Y].length) { + retval = ErrorEval.VALUE_INVALID; + } + } + + if (retval == null) { + double d = MathX.sumxmy2(values[X], values[Y]); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/T.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/T.java index 117e8a1d35..2aa675caad 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/T.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/T.java @@ -4,10 +4,34 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** * @author * */ -public class T extends DefaultFunctionImpl { +public class T implements Function { + + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 1: + if (operands[0] instanceof StringEval + || operands[0] instanceof ErrorEval) { + retval = (ValueEval) operands[0]; + } + else if (operands[0] instanceof ErrorEval) { + retval = StringEval.EMPTY_INSTANCE; + } + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Tan.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Tan.java index 972148acc9..4391b219ce 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Tan.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Tan.java @@ -10,33 +10,20 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * + * */ public class Tan extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 1: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -51,10 +38,12 @@ public class Tan extends NumericFunction { retval = ErrorEval.NUM_ERROR; } } - + if (retval == null) { d = Math.tan(d); - retval = (Double.isNaN(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d); + retval = (Double.isNaN(d)) + ? (ValueEval) ErrorEval.VALUE_INVALID + : new NumberEval(d); } return retval; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Tanh.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Tanh.java index 1c6a1ec262..742ad3018b 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Tanh.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Tanh.java @@ -10,33 +10,20 @@ import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.NumberEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * + * */ public class Tanh extends NumericFunction { - - private static final ValueEvalToNumericXlator NUM_XLATOR = - new ValueEvalToNumericXlator((short) - ( ValueEvalToNumericXlator.BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED - | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED - | ValueEvalToNumericXlator.STRING_IS_PARSED - )); - - protected ValueEvalToNumericXlator getXlator() { - return NUM_XLATOR; - } public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { double d = 0; ValueEval retval = null; - + switch (operands.length) { default: + retval = ErrorEval.VALUE_INVALID; break; case 1: ValueEval ve = singleOperandEvaluate(operands[0], srcRow, srcCol); @@ -51,12 +38,12 @@ public class Tanh extends NumericFunction { retval = ErrorEval.NUM_ERROR; } } - + if (retval == null) { - double ePowX = Math.pow(E, d); - double ePowNegX = Math.pow(E, -d); - d = (ePowX - ePowNegX) / (ePowX + ePowNegX); - retval = (Double.isNaN(d)) ? (ValueEval) ErrorEval.VALUE_INVALID : new NumberEval(d); + d = MathX.tanh(d); + retval = (Double.isNaN(d) || Double.isInfinite(d)) + ? (ValueEval) ErrorEval.NUM_ERROR + : new NumberEval(d); } return retval; } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Upper.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Upper.java index 46d137249c..4618a2b1e3 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Upper.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Upper.java @@ -4,10 +4,46 @@ */ package org.apache.poi.hssf.record.formula.functions; +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.StringValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + /** - * @author + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Upper extends DefaultFunctionImpl { +public class Upper extends TextFunction { + + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + ValueEval retval = null; + String s = null; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + break; + case 1: + ValueEval ve = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol); + if (ve instanceof StringValueEval) { + StringValueEval sve = (StringValueEval) ve; + s = sve.getStringValue(); + } + else if (ve instanceof BlankEval) {} + else { + retval = ErrorEval.VALUE_INVALID; + break; + } + } + + if (retval == null) { + s = (s == null) ? EMPTY_STRING : s; + retval = new StringEval(s.toUpperCase()); + } + + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java b/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java index 6d6aa1bf56..850fbd1a1b 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java +++ b/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java @@ -280,7 +280,6 @@ public class HSSFFormulaEvaluator { protected static ValueEval internalEvaluate(HSSFCell srcCell, HSSFRow srcRow, HSSFSheet sheet, HSSFWorkbook workbook) { int srcRowNum = srcRow.getRowNum(); short srcColNum = srcCell.getCellNum(); - FormulaParser parser = new FormulaParser(srcCell.getCellFormula(), workbook.getWorkbook()); parser.parse(); Ptg[] ptgs = parser.getRPNPtg(); @@ -314,9 +313,6 @@ public class HSSFFormulaEvaluator { // storing the ops in reverse order since they are popping for (int j = numops - 1; j >= 0; j--) { Eval p = (Eval) stack.pop(); - if (p instanceof ErrorEval) { // fast fail - return (ErrorEval) p; - } ops[j] = p; } Eval opresult = operation.evaluate(ops, srcRowNum, srcColNum); @@ -482,7 +478,7 @@ public class HSSFFormulaEvaluator { retval = new StringEval(cell.getStringCellValue()); break; case HSSFCell.CELL_TYPE_FORMULA: - retval = (ValueEval) internalEvaluate(cell, row, sheet, workbook); + retval = internalEvaluate(cell, row, sheet, workbook); break; case HSSFCell.CELL_TYPE_BOOLEAN: retval = cell.getBooleanCellValue() ? BoolEval.TRUE : BoolEval.FALSE; diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls b/src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls index e7921e3d11049f43db96fc68ad976b539ed62d33..5920863cf6a49c52ea93d0e3797deb2554476aa0 100644 GIT binary patch literal 121856 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 E0*2aw5dZ)H literal 92160 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ℜF+rlQTl{FWkW z5(iNQh|IN$wg~eEMbsq@q6!e1>lAGj=6XfcX3BggKxE#iC@svJfIg4kK8_fpw&2*| z36Jb4k8Ha~w!5)C{k?r!xp7qFfdt`e&vb`SJ^B&m?9@$GC*}g0p{g(Q}fnREa z$HfLWD|$lEcNI~CIPfb#wB1HU+l6_nBI*zaeg%lk+kiNe-Vw~)I6LM1G@MEIRz~J( zAwmQ*SjXV(&VIOjw!_Y(x$AtqW7w4{a`;qs2i6EN$K~$zfDtYa+Bm|Qw2Q;d25m|^ z>`YpoxjF`C()MFhk(sodTk9B{H!4GN8lEWY7@S9jkAQYyDbUTv$*4r$-MrF1gWh3h z(OmqKxwd14i+?sRGK>Cga%WPW+d39^p+-~F7c)wX{P0O{=@WN~HE)N-9x*4Foq@%y z&iOa`N^W#z&%UI4unNE1f*JHqStZ~)U{`#%rEnqb>$y9V%#WQVvqq)N_tk5jmOT7G zz2@m44_22ulHqgs&f+ys%NoGn%1W-E{nxjkX@sC2XL9dCX5_*ke&}%{sKW)86c3C?Hy=GePM_!%(*SEGY zr=iz42E8U4NBAm_W6*2HEIM}DlUE&(oQALRkWq{yvz^EB$LuF#0rxIFQtm#A*UMzS~D{>1GrvFRPK zDc4JO1vce+%B~FiSxMAhRuZ+3l|=19pWBtB{_P7syJQ8&Y1-bUX5HPW4sC2vomoj# zKQ;#IvG#7X#B5F3+T*x9_2FlwygyVQel{qt_2H+Joo!7=oAkQ)@UxOaa5A1*R@Q-F+0`qeK_N{^4;+wR-y+a*ZU)(KEOq?!kOi}GvNmLtF5-qunGi*;eqQHTS>Wh1% zWOpmtE9l3HIHtgXi~(YQeXpVygn6GLjw)~s zk$vKkwR>dzA-ib)*y2!sIQUX+@T%D0XNq1E^m9ejAP&9^5N)?v(SBk6LJ@U{gD(R_ z=7T_mu-)51oiL_c>SU*OjO)tH`0mn%y)CtbK5jqY2d$iAu-4cQM_vdK^wf^QTJ(>z z&in1#Pg#ca!}0*tF>D()0MT%l&fB&PlV_)7R6=6=;gG>M6Z_d@%hN$_BO^G;i}c0P zTDp|N5gY@*jVHQjEz1m^mN*7$YS^B>9T~wn25WBkc^e}*iKBy!gSll*esJx`*M9Rx zgXBZnF#ayD?38n5V(qpcs~72q-%1{^V?4)VuN2LXyjEL?@nWZRXQoKMIUp9_0;}@L z?g6!Gd3AJ*XHSGbAWwarHQ34=kT%V}A$36XY~PSXHY9&;L}*8W2Xqw3KL3D@0_}TK z2Qo@+@7ogEUwl50WJ&Dkko7fX9#WrtM{@rwMF#~vtcW!hM}G#0-usB64}|%sBGy?P z{TU!K(~1rW^D#xNwK)1SKx96y=o4W+p@{W1Wu6QWnZHqlW*_J&AhwVnWjw)oEwL%m zGV-k^_hwUmR;_2Nne@ntJhEbstkfeb^T;}TWaS=NH;=5lN7ln5>*y<9pZ@90Fn8$qB3FbQbaAL z%rgNZ^N)(kh54)^>JdkO28hf*De5lF|5ijz;^@x+k-1kZU?|JY&S zk&W`mMtfvqJhHJK**K4^$|I|WEUGK|E%k>ZR@Dam#Re}c8X)KuMbsdUSPc+u_nM-? z!hBs3b%-NY14QNJ0V4CSibe_ZZ;Gf%9Q_#} zG7kdD4vT_tD;ayZw2Tw{l~kS+tEjkF3{N#_DeYiM;3=>lnndF#ffS% z!r75yaAfhLS09}>;O#>ahm0(wzjq9dEW*#|0+}7jRxroNoZ*iy&>a>S5jY0>!DuQv z!&e6OJQQ$L5oO3Od+vHCGjlQJfqSTL@jAdOk7OO1N? z)8mJqJL9>(!KV<)>K_M0VB1~5qJ9pa@yNe_`_dc2;&@cz;^w>{Pt;t&fIs)!bnBbK z((x!f$K{%uT>pOeUwm{fS8T=>=!zm%5ga3PJUX^O=G8L4cR9}Vn6aV9$Qu`q#W87A zi!vtVx+AxGBQ>^CY(tBV6FcZ(D;e6R2aLhuCdRUc|;vb5t1$_v_{%(8W|7!2tgR7|SIDYO;0to~O zkrt5G6_tljFo2cvOd#?SO3Ispg^*lGG0_1d+x~+~>&Ug2Gzx&&B&i>BXy?f4{ z-EG;DZ8=h5L*yi%F*wb&n*Q4+5o619xU^!AHpQb&^=J=yv>6_4mPae`XmdQ;T#vTE zqb>Aki#^&BkG9mKEo-HzCdq%Cy6kpotC<6)|B)+>O|_O+9g`1v zHFLmZdEK!Y){?=lwjRriJk${|SwzA)uy&@m zkstL%t~&Qcu6M`eU2U&e=T_J9K`x$9GB&7vsDuhZLqB7(I&lyc^|Mtz zWleiys#9;unJN+$2*b2llV-|VU&rd~Rx!s^B)o?>V6yDz*amBPmt!gvh7Si!miIVT zZ!P=7RQ>f}@Mi~_E%?;ev2==VAjXzODs78Ld&;A2^Jv>W+76HQtVi4F(RO*X-5za^ zN89VsUi4`DJ=y_}cCeMEa+UuWrtQk0!Ir^5$F^8D$T4}4VcG#x*$sAVo3$L`n0&}E z?SRR0sAD^<F(+D|;%X^-}%M?34$8a>*%R+{Rq{Kv3cR|bb|85BBp#IhpCve+^CkYTq0ljUT`PFTw+j>(G*yA7Bur#beTwVdvl{K&A|fXQ-(W3OAw znU2YmG>`)(%UO<{ww5K1$(OuqHej-x?bumsIma=1li{ENljS_e&RNU(u(s6Ow}`QI zy*=;Ie(BNPX{D(g6(7S;U7p^ud0Ob$dCL|#rWhH98Zhn4V#nUGmP=s2%vxIqkw`m~Dh{JN~8>MvbP^KV5fX+QowD+osO^?dFM7|Dk|zS+yn+t6UwMoUE>@O_V;kwlq;&no6>wCYGp7r4sR2 zdF6@~@#^^MRIDPtx-1?`Rm5ZQx;62#RJ=SU`*=;Pv^pNENe+$8iDMsM8!Jzi)mE`d zX{s{0TJb+py0$d7qB0R5I@abT$HeFc%p%7{G(b0+LiGyX){A}F#g{ha9UQNmn(@(m z^D|w!n?le$72)#?eDo`>atxPLl($S&(3#rQO0*%gHZ5gj$SRudQHtP5g(MM&QjD-9 z6#0;+!RasH*O~Zd@{3SXI#TrM@hsC7Th)~;tat-HzYb*mFEF~fz{>1yKsM=#ZLc$# zVq1?)PBz8WF3(Kvexdyb^#rLA9i!<;wLvHFz?g`+eO!dF63%5_uB;R8!rWGNbLH5_ zznQtbWWrLb-)r^3cD~sv^|mr7M#JYJV<)Y_SzD8}3gc69DcnHcj4*WFnvn8>;I zxQIO{XvbBlcB&uqoz9Hl^-R+(VhWnA)aj<()+73{bLzt430lh#7?P#AKC(;H=3G&C z*7gIkpLpfNKb?8zOrshC5xSlFzOYZznZ}|&ql^F(BbK_`|pZ$kS^I0z))r#@|D~C(-;gQ}i z&2Qqov=POiDc9$`^r~?FA9>&!CyT6z>glH^IsW3-1Ao0dt0M3CbJ=F_fKwmbhjuqB zbduBhI-o7-_hPAZ{z&9~SSoG(g|-eWuF~>&O+{7hstUrvdbFE`l~?8J{I??to35KL4s+r9*s&k~e$m?z`5>G^4}=~FJrH^z^g!r=&;y|dLJx!< z2t5#bAoRe0qX%x*{*S(Y;r;zXd*Lav%dtW{k{<7fn`AL zcD2FP6}<+iOSBHCeSZivx98Pnex*|fyFJ0rUGngU?PE|s!kmhDJXK)36l`$#jo=8A zi=iS{LtdF$kgQ%+qYY~8_F)?xpM+EBfzSh?2SN{o9tb@UdLZ;b=z-7!p$9?_{NH&% z?RYhp)h^b(d)*7yJ$tpYb+2Cc>2+USO=-2=)sENwe~k}PTfYm?m_N1mn}=Vi&98oe z?w|+IxFZcw>IHfOHO>2i7`PMk19ySD!9Acq7yt%>LEv667z_bl0z<(ta33fD!@&qJ z65J2I3^ZPC6!;1l4aR`6U>q0^7$al~K@pe;CV^t`AeaoM0QGN71Jl7nUcg7K0_=Vek#G6f6U!U^yrQ<8Zi-v