From: Avik Sengupta Date: Thu, 9 Jun 2005 18:34:57 +0000 (+0000) Subject: New formula eval stuff - added functions and refactored, by Amol X-Git-Tag: BEFORE_RICHTEXT~55 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=f52e1b0daff3aadbe80cb9a92521756f97860eaf;p=poi.git 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 --- 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 e7921e3d11..5920863cf6 100644 Binary files a/src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls and b/src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls differ diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/GenericFormulaTestCase.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/GenericFormulaTestCase.java index 57e1375817..ded15ffeba 100644 --- a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/GenericFormulaTestCase.java +++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/GenericFormulaTestCase.java @@ -4,12 +4,12 @@ */ package org.apache.poi.hssf.record.formula.eval; -import java.io.File; import java.io.FileInputStream; import junit.framework.AssertionFailedError; import junit.framework.TestCase; +import org.apache.poi.hssf.record.formula.functions.TestMathX; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFRow; @@ -77,12 +77,13 @@ public class GenericFormulaTestCase extends TestCase { assertEquals(msg, HSSFCell.CELL_TYPE_ERROR, actual.getCellType()); // TODO: check if exact error matches break; case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation - throw new AssertionFailedError("Cannot expect formula as result of formula evaluation"); + throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg); case HSSFCell.CELL_TYPE_NUMERIC: assertEquals(msg, HSSFCell.CELL_TYPE_NUMERIC, actual.getCellType()); - double delta = Math.abs(expected.getNumericCellValue()-actual.getNumberValue()); - double pctExpected = Math.abs(0.00001*expected.getNumericCellValue()); - assertTrue(msg, delta <= pctExpected); + TestMathX.assertEquals(msg, expected.getNumericCellValue(), actual.getNumberValue(), TestMathX.POS_ZERO, TestMathX.DIFF_TOLERANCE_FACTOR); +// double delta = Math.abs(expected.getNumericCellValue()-actual.getNumberValue()); +// double pctExpected = Math.abs(0.00001*expected.getNumericCellValue()); +// assertTrue(msg, delta <= pctExpected); break; case HSSFCell.CELL_TYPE_STRING: assertEquals(msg, HSSFCell.CELL_TYPE_STRING, actual.getCellType()); @@ -113,18 +114,20 @@ public class GenericFormulaTestCase extends TestCase { HSSFCell c = null; for (short colnum=getBeginCol(); colnum < endcolnum; colnum++) { + try { c = r.getCell(colnum); - if (c==null || c.getCellType() == HSSFCell.CELL_TYPE_BLANK) + if (c==null || c.getCellType() != HSSFCell.CELL_TYPE_FORMULA) continue; - assertEquals("Sanity check input cell type ", HSSFCell.CELL_TYPE_FORMULA, c.getCellType()); - HSSFFormulaEvaluator.CellValue actualValue = evaluator.evaluate(c); HSSFCell expectedValueCell = getExpectedValueCell(s, r, c); assertEquals("Formula: " + c.getCellFormula() + " @ " + getBeginRow() + ":" + colnum, expectedValueCell, actualValue); + } catch (RuntimeException re) { + throw new RuntimeException("CELL["+getBeginRow()+","+colnum+"]: "+re.getMessage(), re); + } } } diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestEverything.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestEverything.java index 6c30b30fb7..85f51af600 100644 --- a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestEverything.java +++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestEverything.java @@ -21,6 +21,7 @@ public class TestEverything extends TestSuite { s = "D"+Integer.toString(i).trim(); suite.addTest(new GenericFormulaTestCase(s)); } +// suite.addTest(new GenericFormulaTestCase("D1164")); return suite; } }