diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java index cfe88369e4..1fa5a38614 100644 --- a/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java +++ b/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java @@ -52,8 +52,8 @@ public final class FunctionEval { retval[0] = new Count(); retval[1] = new If(); - retval[2] = new IsNa(); - retval[3] = new IsError(); + retval[2] = LogicalFunction.ISNA; + retval[3] = LogicalFunction.ISERROR; retval[ID.SUM] = AggregateFunction.SUM; retval[5] = AggregateFunction.AVERAGE; retval[6] = AggregateFunction.MIN; @@ -69,7 +69,7 @@ public final class FunctionEval { retval[16] = NumericFunction.COS; retval[17] = NumericFunction.TAN; retval[18] = NumericFunction.ATAN; - retval[19] = new Pi(); + retval[19] = NumericFunction.PI; retval[20] = NumericFunction.SQRT; retval[21] = NumericFunction.EXP; retval[22] = NumericFunction.LN; @@ -84,11 +84,11 @@ public final class FunctionEval { retval[31] = TextFunction.MID; retval[32] = TextFunction.LEN; retval[33] = new Value(); - retval[34] = new True(); - retval[35] = new False(); - retval[36] = new And(); - retval[37] = new Or(); - retval[38] = new Not(); + retval[34] = BooleanFunction.TRUE; + retval[35] = BooleanFunction.FALSE; + retval[36] = BooleanFunction.AND; + retval[37] = BooleanFunction.OR; + retval[38] = BooleanFunction.NOT; retval[39] = NumericFunction.MOD; retval[56] = FinanceFunction.PV; @@ -96,7 +96,7 @@ public final class FunctionEval { retval[58] = FinanceFunction.NPER; retval[59] = FinanceFunction.PMT; - retval[63] = new Rand(); + retval[63] = NumericFunction.RAND; retval[64] = new Match(); retval[65] = DateFunc.instance; retval[66] = new Time(); @@ -108,6 +108,7 @@ public final class FunctionEval { retval[76] = new Rows(); retval[77] = new Columns(); + retval[82] = TextFunction.SEARCH; retval[ID.OFFSET] = new Offset(); retval[82] = TextFunction.SEARCH; @@ -118,7 +119,7 @@ public final class FunctionEval { retval[101] = new Hlookup(); retval[102] = new Vlookup(); - retval[105] = new Isref(); + retval[105] = LogicalFunction.ISREF; retval[109] = NumericFunction.LOG; @@ -134,9 +135,9 @@ public final class FunctionEval { retval[124] = TextFunction.FIND; - retval[127] = LogicalFunction.IsText; - retval[128] = LogicalFunction.IsNumber; - retval[129] = new Isblank(); + retval[127] = LogicalFunction.ISTEXT; + retval[128] = LogicalFunction.ISNUMBER; + retval[129] = LogicalFunction.ISBLANK; retval[130] = new T(); retval[ID.INDIRECT] = null; // Indirect.evaluate has different signature @@ -146,9 +147,9 @@ public final class FunctionEval { retval[183] = AggregateFunction.PRODUCT; retval[184] = NumericFunction.FACT; - retval[190] = LogicalFunction.IsNonText; + retval[190] = LogicalFunction.ISNONTEXT; - retval[198] = LogicalFunction.IsLogical; + retval[198] = LogicalFunction.ISLOGICAL; retval[212] = NumericFunction.ROUNDUP; retval[213] = NumericFunction.ROUNDDOWN; diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/AggregateFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/AggregateFunction.java index 6397ea39f5..2df9dd3e57 100644 --- a/src/java/org/apache/poi/hssf/record/formula/functions/AggregateFunction.java +++ b/src/java/org/apache/poi/hssf/record/formula/functions/AggregateFunction.java @@ -19,13 +19,67 @@ 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.EvaluationException; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.OperandResolver; +import org.apache.poi.hssf.record.formula.eval.ValueEval; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * */ public abstract class AggregateFunction extends MultiOperandNumericFunction { + private static final class LargeSmall extends Fixed2ArgFunction { + private final boolean _isLarge; + protected LargeSmall(boolean isLarge) { + _isLarge = isLarge; + } + + public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, + ValueEval arg1) { + double dn; + try { + ValueEval ve1 = OperandResolver.getSingleValue(arg1, srcRowIndex, srcColumnIndex); + dn = OperandResolver.coerceValueToDouble(ve1); + } catch (EvaluationException e1) { + // all errors in the second arg translate to #VALUE! + return ErrorEval.VALUE_INVALID; + } + // weird Excel behaviour on second arg + if (dn < 1.0) { + // values between 0.0 and 1.0 result in #NUM! + return ErrorEval.NUM_ERROR; + } + // all other values are rounded up to the next integer + int k = (int) Math.ceil(dn); + + double result; + try { + double[] ds = ValueCollector.collectValues(arg0); + if (k > ds.length) { + return ErrorEval.NUM_ERROR; + } + result = _isLarge ? StatsLib.kthLargest(ds, k) : StatsLib.kthSmallest(ds, k); + NumericFunction.checkValue(result); + } catch (EvaluationException e) { + return e.getErrorEval(); + } + + return new NumberEval(result); + } + } + private static final class ValueCollector extends MultiOperandNumericFunction { + private static final ValueCollector instance = new ValueCollector(); + public ValueCollector() { + super(false, false); + } + public static double[] collectValues(ValueEval...operands) throws EvaluationException { + return instance.getNumberArray(operands); + } + protected double evaluate(double[] values) { + throw new IllegalStateException("should not be called"); + } + } + protected AggregateFunction() { super(false, false); } @@ -48,17 +102,7 @@ public abstract class AggregateFunction extends MultiOperandNumericFunction { return StatsLib.devsq(values); } }; - public static final Function LARGE = new AggregateFunction() { - protected double evaluate(double[] ops) throws EvaluationException { - if (ops.length < 2) { - throw new EvaluationException(ErrorEval.NUM_ERROR); - } - double[] values = new double[ops.length-1]; - int k = (int) ops[ops.length-1]; - System.arraycopy(ops, 0, values, 0, values.length); - return StatsLib.kthLargest(values, k); - } - }; + public static final Function LARGE = new LargeSmall(true); public static final Function MAX = new AggregateFunction() { protected double evaluate(double[] values) { return values.length > 0 ? MathX.max(values) : 0; @@ -79,17 +123,7 @@ public abstract class AggregateFunction extends MultiOperandNumericFunction { return MathX.product(values); } }; - public static final Function SMALL = new AggregateFunction() { - protected double evaluate(double[] ops) throws EvaluationException { - if (ops.length < 2) { - throw new EvaluationException(ErrorEval.NUM_ERROR); - } - double[] values = new double[ops.length-1]; - int k = (int) ops[ops.length-1]; - System.arraycopy(ops, 0, values, 0, values.length); - return StatsLib.kthSmallest(values, k); - } - }; + public static final Function SMALL = new LargeSmall(false); public static final Function STDEV = new AggregateFunction() { protected double evaluate(double[] values) throws EvaluationException { if (values.length < 1) { diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/And.java b/src/java/org/apache/poi/hssf/record/formula/functions/And.java deleted file mode 100644 index e024562865..0000000000 --- a/src/java/org/apache/poi/hssf/record/formula/functions/And.java +++ /dev/null @@ -1,32 +0,0 @@ -/* ==================================================================== - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -==================================================================== */ - -package org.apache.poi.hssf.record.formula.functions; - -/** - * - */ -public final class And extends BooleanFunction { - - protected boolean getInitialResultValue() { - return true; - } - - protected boolean partialEvaluate(boolean cumulativeResult, boolean currentValue) { - return cumulativeResult && currentValue; - } -} diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/BooleanFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/BooleanFunction.java index 4e959a61e5..0165e501a5 100644 --- a/src/java/org/apache/poi/hssf/record/formula/functions/BooleanFunction.java +++ b/src/java/org/apache/poi/hssf/record/formula/functions/BooleanFunction.java @@ -101,4 +101,46 @@ public abstract class BooleanFunction implements Function { protected abstract boolean getInitialResultValue(); protected abstract boolean partialEvaluate(boolean cumulativeResult, boolean currentValue); + + + public static final Function AND = new BooleanFunction() { + protected boolean getInitialResultValue() { + return true; + } + protected boolean partialEvaluate(boolean cumulativeResult, boolean currentValue) { + return cumulativeResult && currentValue; + } + }; + public static final Function OR = new BooleanFunction() { + protected boolean getInitialResultValue() { + return false; + } + protected boolean partialEvaluate(boolean cumulativeResult, boolean currentValue) { + return cumulativeResult || currentValue; + } + }; + public static final Function FALSE = new Fixed0ArgFunction() { + public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) { + return BoolEval.FALSE; + } + }; + public static final Function TRUE = new Fixed0ArgFunction() { + public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) { + return BoolEval.TRUE; + } + }; + public static final Function NOT = new Fixed1ArgFunction() { + public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) { + boolean boolArgVal; + try { + ValueEval ve = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex); + Boolean b = OperandResolver.coerceValueToBoolean(ve, false); + boolArgVal = b == null ? false : b.booleanValue(); + } catch (EvaluationException e) { + return e.getErrorEval(); + } + + return BoolEval.valueOf(!boolArgVal); + } + }; } diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java index 2de9ab1350..c101f2dc9e 100644 --- a/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java +++ b/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java @@ -17,17 +17,58 @@ package org.apache.poi.hssf.record.formula.functions; +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.EvaluationException; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * Super class for all Evals for financial function evaluation. - * */ -public abstract class FinanceFunction extends NumericFunction.MultiArg { +public abstract class FinanceFunction implements Function3Arg, Function4Arg { + private static final ValueEval DEFAULT_ARG3 = NumberEval.ZERO; + private static final ValueEval DEFAULT_ARG4 = BoolEval.FALSE; + protected FinanceFunction() { - super (3, 5); + // no instance fields + } + + public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, + ValueEval arg2) { + return evaluate(srcRowIndex, srcColumnIndex, arg0, arg1, arg2, DEFAULT_ARG3); + } + public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, + ValueEval arg2, ValueEval arg3) { + return evaluate(srcRowIndex, srcColumnIndex, arg0, arg1, arg2, arg3, DEFAULT_ARG4); + } + public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, + ValueEval arg2, ValueEval arg3, ValueEval arg4) { + double result; + try { + double d0 = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex); + double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex); + double d2 = NumericFunction.singleOperandEvaluate(arg2, srcRowIndex, srcColumnIndex); + double d3 = NumericFunction.singleOperandEvaluate(arg3, srcRowIndex, srcColumnIndex); + double d4 = NumericFunction.singleOperandEvaluate(arg4, srcRowIndex, srcColumnIndex); + result = evaluate(d0, d1, d2, d3, d4 != 0.0); + NumericFunction.checkValue(result); + } catch (EvaluationException e) { + return e.getErrorEval(); + } + return new NumberEval(result); + } + public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) { + switch (args.length) { + case 3: + return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2], DEFAULT_ARG3, DEFAULT_ARG4); + case 4: + return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2], args[3], DEFAULT_ARG4); + case 5: + return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2], args[3], args[4]); + } + return ErrorEval.VALUE_INVALID; } protected double evaluate(double[] ds) throws EvaluationException { diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java b/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java index 0a25044f33..03faa25b55 100644 --- a/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java +++ b/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java @@ -18,7 +18,7 @@ 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.BoolEval; import org.apache.poi.hssf.record.formula.eval.EvaluationException; import org.apache.poi.hssf.record.formula.eval.OperandResolver; import org.apache.poi.hssf.record.formula.eval.ValueEval; @@ -39,27 +39,24 @@ import org.apache.poi.hssf.record.formula.functions.LookupUtils.ValueVector; * * @author Josh Micich */ -public final class Hlookup implements Function { +public final class Hlookup extends Var3or4ArgFunction { + private static final ValueEval DEFAULT_ARG3 = BoolEval.TRUE; - public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) { - ValueEval arg3 = null; - switch(args.length) { - case 4: - arg3 = args[3]; // important: assumed array element is never null - case 3: - break; - default: - // wrong number of arguments - return ErrorEval.VALUE_INVALID; - } + public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, + ValueEval arg2) { + return evaluate(srcRowIndex, srcColumnIndex, arg0, arg1, arg2, DEFAULT_ARG3); + } + + public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, + ValueEval arg2, ValueEval arg3) { try { // Evaluation order: // arg0 lookup_value, arg1 table_array, arg3 range_lookup, find lookup value, arg2 row_index, fetch result - ValueEval lookupValue = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol); - AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]); - boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol); + ValueEval lookupValue = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex); + AreaEval tableArray = LookupUtils.resolveTableArrayArg(arg1); + boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcRowIndex, srcColumnIndex); int colIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createRowVector(tableArray, 0), isRangeLookup); - int rowIndex = LookupUtils.resolveRowOrColIndexArg(args[2], srcCellRow, srcCellCol); + int rowIndex = LookupUtils.resolveRowOrColIndexArg(arg2, srcRowIndex, srcColumnIndex); ValueVector resultCol = createResultColumnVector(tableArray, rowIndex); return resultCol.getItem(colIndex); } catch (EvaluationException e) { @@ -67,7 +64,6 @@ public final class Hlookup implements Function { } } - /** * Returns one column from an AreaEval * diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Hyperlink.java b/src/java/org/apache/poi/hssf/record/formula/functions/Hyperlink.java index 703af9716c..761c5f3a63 100644 --- a/src/java/org/apache/poi/hssf/record/formula/functions/Hyperlink.java +++ b/src/java/org/apache/poi/hssf/record/formula/functions/Hyperlink.java @@ -17,9 +17,6 @@ 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.EvaluationException; -import org.apache.poi.hssf.record.formula.eval.OperandResolver; import org.apache.poi.hssf.record.formula.eval.StringEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; @@ -36,21 +33,17 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval; * friendly_name (optional) the value to display
* * Returns last argument. Leaves type unchanged (does not convert to {@link StringEval}). - + * * @author Wayne Clingingsmith */ -public final class Hyperlink implements Function { +public final class Hyperlink extends Var1or2ArgFunction { - public ValueEval evaluate(ValueEval[] operands, int srcRow, int srcCol) { - int lastArgIx = operands.length - 1; - if (lastArgIx < 0 || lastArgIx > 1) { - return ErrorEval.VALUE_INVALID; - } - - try { - return OperandResolver.getSingleValue(operands[lastArgIx], srcRow, srcCol); - } catch (EvaluationException e) { - return e.getErrorEval(); - } + public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) { + return arg0; + } + public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) { + // note - if last arg is MissingArgEval, result will be NumberEval.ZERO, + // but WorkbookEvaluator does that translation + return arg1; } } diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Index.java b/src/java/org/apache/poi/hssf/record/formula/functions/Index.java index 49e7484fa7..ad1dc9dd2b 100644 --- a/src/java/org/apache/poi/hssf/record/formula/functions/Index.java +++ b/src/java/org/apache/poi/hssf/record/formula/functions/Index.java @@ -44,56 +44,71 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval; * * @author Josh Micich */ -public final class Index implements Function { +public final class Index implements Function2Arg, Function3Arg, Function4Arg { - public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) { - int nArgs = args.length; - if(nArgs < 2) { - // too few arguments - return ErrorEval.VALUE_INVALID; - } - ValueEval firstArg = args[0]; - if (firstArg instanceof RefEval) { - // convert to area ref for simpler code in getValueFromArea() - firstArg = ((RefEval)firstArg).offset(0, 0, 0, 0); - } - if(!(firstArg instanceof AreaEval)) { + public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) { + AreaEval reference = convertFirstArg(arg0); - // else the other variation of this function takes an array as the first argument - // it seems like interface 'ArrayEval' does not even exist yet - throw new RuntimeException("Incomplete code - cannot handle first arg of type (" - + firstArg.getClass().getName() + ")"); - } - AreaEval reference = (AreaEval) firstArg; - - int rowIx = 0; - int columnIx = 0; boolean colArgWasPassed = false; + int columnIx = 0; try { - switch(nArgs) { - case 4: - throw new RuntimeException("Incomplete code" + - " - don't know how to support the 'area_num' parameter yet)"); - // Excel expression might look like this "INDEX( (A1:B4, C3:D6, D2:E5 ), 1, 2, 3) - // In this example, the 3rd area would be used i.e. D2:E5, and the overall result would be E2 - // Token array might be encoded like this: MemAreaPtg, AreaPtg, AreaPtg, UnionPtg, UnionPtg, ParenthesesPtg - // The formula parser doesn't seem to support this yet. Not sure if the evaluator does either - - case 3: - columnIx = resolveIndexArg(args[2], srcCellRow, srcCellCol); - colArgWasPassed = true; - case 2: - rowIx = resolveIndexArg(args[1], srcCellRow, srcCellCol); - break; - default: - // too many arguments - return ErrorEval.VALUE_INVALID; - } - return getValueFromArea(reference, rowIx, columnIx, colArgWasPassed, srcCellRow, srcCellCol); + int rowIx = resolveIndexArg(arg1, srcRowIndex, srcColumnIndex); + return getValueFromArea(reference, rowIx, columnIx, colArgWasPassed, srcRowIndex, srcColumnIndex); } catch (EvaluationException e) { return e.getErrorEval(); } } + public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, + ValueEval arg2) { + AreaEval reference = convertFirstArg(arg0); + + boolean colArgWasPassed = true; + try { + int columnIx = resolveIndexArg(arg2, srcRowIndex, srcColumnIndex); + int rowIx = resolveIndexArg(arg1, srcRowIndex, srcColumnIndex); + return getValueFromArea(reference, rowIx, columnIx, colArgWasPassed, srcRowIndex, srcColumnIndex); + } catch (EvaluationException e) { + return e.getErrorEval(); + } + } + public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, + ValueEval arg2, ValueEval arg3) { + throw new RuntimeException("Incomplete code" + + " - don't know how to support the 'area_num' parameter yet)"); + // Excel expression might look like this "INDEX( (A1:B4, C3:D6, D2:E5 ), 1, 2, 3) + // In this example, the 3rd area would be used i.e. D2:E5, and the overall result would be E2 + // Token array might be encoded like this: MemAreaPtg, AreaPtg, AreaPtg, UnionPtg, UnionPtg, ParenthesesPtg + // The formula parser doesn't seem to support this yet. Not sure if the evaluator does either + } + + private static AreaEval convertFirstArg(ValueEval arg0) { + ValueEval firstArg = arg0; + if (firstArg instanceof RefEval) { + // convert to area ref for simpler code in getValueFromArea() + return ((RefEval)firstArg).offset(0, 0, 0, 0); + } + if((firstArg instanceof AreaEval)) { + return (AreaEval) firstArg; + } + // else the other variation of this function takes an array as the first argument + // it seems like interface 'ArrayEval' does not even exist yet + throw new RuntimeException("Incomplete code - cannot handle first arg of type (" + + firstArg.getClass().getName() + ")"); + + } + + public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) { + switch (args.length) { + case 2: + return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1]); + case 3: + return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2]); + case 4: + return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2], args[3]); + } + return ErrorEval.VALUE_INVALID; + } + /** * @param colArgWasPassedfalse
if the INDEX argument list had just 2 items
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/IsError.java b/src/java/org/apache/poi/hssf/record/formula/functions/IsError.java
deleted file mode 100644
index 654f4d7968..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/IsError.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.record.formula.functions;
-
-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.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Josh Micich
- */
-public final class IsError implements Function {
-
- public ValueEval evaluate(ValueEval[] operands, int srcCellRow, int srcCellCol) {
- if (operands.length != 1) {
- return ErrorEval.VALUE_INVALID;
- }
- try {
- OperandResolver.getSingleValue(operands[0], srcCellRow, srcCellCol);
- } catch (EvaluationException e) {
- return BoolEval.TRUE;
- }
- return BoolEval.FALSE;
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/IsNa.java b/src/java/org/apache/poi/hssf/record/formula/functions/IsNa.java
deleted file mode 100644
index 316a29ec4d..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/IsNa.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.record.formula.functions;
-
-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.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.ss.usermodel.ErrorConstants;
-
-/**
- * Implementation for Excel ISNA() function.
- *
- * Syntax:null
*/
public static boolean resolveRangeLookupArg(ValueEval rangeLookupArg, int srcCellRow, int srcCellCol) throws EvaluationException {
- if(rangeLookupArg == null) {
- // range_lookup arg not provided
- return true; // default is TRUE
- }
+
ValueEval valEval = OperandResolver.getSingleValue(rangeLookupArg, srcCellRow, srcCellCol);
if(valEval instanceof BlankEval) {
// Tricky:
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Not.java b/src/java/org/apache/poi/hssf/record/formula/functions/Not.java
deleted file mode 100644
index 792ee3a025..0000000000
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Not.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.record.formula.functions;
-
-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.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-
-/**
- * @author Amol S. Deshmukh < amol at apache dot org >
- * The NOT boolean function. Returns negation of specified value
- * (treated as a boolean). If the specified arg is a number,
- * then it is true <=> 'number is non-zero'
- */
-public final class Not implements Function {
-
- public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
- if (args.length != 1) {
- return ErrorEval.VALUE_INVALID;
- }
- boolean boolArgVal;
- try {
- ValueEval ve = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
- Boolean b = OperandResolver.coerceValueToBoolean(ve, false);
- boolArgVal = b == null ? false : b.booleanValue();
- } catch (EvaluationException e) {
- return e.getErrorEval();
- }
-
- return BoolEval.valueOf(!boolArgVal);
- }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Npv.java b/src/java/org/apache/poi/hssf/record/formula/functions/Npv.java
index 114aa4d02e..99955301e7 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Npv.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Npv.java
@@ -17,7 +17,10 @@
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.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
* Calculates the net present value of an investment by using a discount rate
@@ -25,23 +28,80 @@ import org.apache.poi.hssf.record.formula.eval.EvaluationException;
* values). Minimum 2 arguments, first arg is the rate of discount over the
* length of one period others up to 254 arguments representing the payments and
* income.
- *
+ *
* @author SPetrakovsky
*/
-public class Npv extends NumericFunction.MultiArg {
+public final class Npv implements Function2Arg, Function3Arg, Function4Arg {
- public Npv() {
- super(2, 255);
+
+ public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
+ double result;
+ try {
+ double rate = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+ double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+ result = evaluate(rate, d1);
+ NumericFunction.checkValue(result);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ return new NumberEval(result);
+ }
+ public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+ ValueEval arg2) {
+ double result;
+ try {
+ double rate = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+ double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+ double d2 = NumericFunction.singleOperandEvaluate(arg2, srcRowIndex, srcColumnIndex);
+ result = evaluate(rate, d1, d2);
+ NumericFunction.checkValue(result);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ return new NumberEval(result);
+ }
+ public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+ ValueEval arg2, ValueEval arg3) {
+ double result;
+ try {
+ double rate = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+ double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+ double d2 = NumericFunction.singleOperandEvaluate(arg2, srcRowIndex, srcColumnIndex);
+ double d3 = NumericFunction.singleOperandEvaluate(arg3, srcRowIndex, srcColumnIndex);
+ result = evaluate(rate, d1, d2, d3);
+ NumericFunction.checkValue(result);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ return new NumberEval(result);
}
- @Override
- protected double evaluate(double[] ds) throws EvaluationException {
- double rate = ds[0];
+ public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ int nArgs = args.length;
+ if (nArgs<2) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ int np = nArgs-1;
+ double[] ds = new double[np];
+ double result;
+ try {
+ double rate = NumericFunction.singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex);
+ for (int i = 0; i < ds.length; i++) {
+ ds[i] = NumericFunction.singleOperandEvaluate(args[i+1], srcRowIndex, srcColumnIndex);
+ }
+ result = evaluate(rate, ds);
+ NumericFunction.checkValue(result);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ return new NumberEval(result);
+ }
+
+ private static double evaluate(double rate, double...ds) {
double sum = 0;
- for (int i = 1; i < ds.length; i++) {
+ for (int i = 0; i < ds.length; i++) {
sum += ds[i] / Math.pow(rate + 1, i);
}
return sum;
}
-
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java
index 24b0ae2692..3d32925ae3 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java
@@ -25,6 +25,7 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ * @author Josh Micich
*/
public abstract class NumericFunction implements Function {
@@ -32,8 +33,8 @@ public abstract class NumericFunction implements Function {
static final double TEN = 10.0;
static final double LOG_10_TO_BASE_e = Math.log(TEN);
- protected static final double singleOperandEvaluate(ValueEval arg, int srcCellRow, int srcCellCol) throws EvaluationException {
- ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+ protected static final double singleOperandEvaluate(ValueEval arg, int srcRowIndex, int srcColumnIndex) throws EvaluationException {
+ ValueEval ve = OperandResolver.getSingleValue(arg, srcRowIndex, srcColumnIndex);
double result = OperandResolver.coerceValueToDouble(ve);
checkValue(result);
return result;
@@ -64,10 +65,21 @@ public abstract class NumericFunction implements Function {
/* -------------------------------------------------------------------------- */
// intermediate sub-classes (one-arg, two-arg and multi-arg)
- public static abstract class OneArg extends NumericFunction {
+ public static abstract class OneArg extends Fixed1ArgFunction {
protected OneArg() {
// no fields to initialise
}
+ public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
+ double result;
+ try {
+ double d = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+ result = evaluate(d);
+ checkValue(result);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ return new NumberEval(result);
+ }
protected final double eval(ValueEval[] args, int srcCellRow, int srcCellCol) throws EvaluationException {
if (args.length != 1) {
throw new EvaluationException(ErrorEval.VALUE_INVALID);
@@ -78,40 +90,26 @@ public abstract class NumericFunction implements Function {
protected abstract double evaluate(double d) throws EvaluationException;
}
- public static abstract class TwoArg extends NumericFunction {
+ public static abstract class TwoArg extends Fixed2ArgFunction {
protected TwoArg() {
// no fields to initialise
}
- protected final double eval(ValueEval[] args, int srcCellRow, int srcCellCol) throws EvaluationException {
- if (args.length != 2) {
- throw new EvaluationException(ErrorEval.VALUE_INVALID);
- }
- double d0 = singleOperandEvaluate(args[0], srcCellRow, srcCellCol);
- double d1 = singleOperandEvaluate(args[1], srcCellRow, srcCellCol);
- return evaluate(d0, d1);
- }
- protected abstract double evaluate(double d0, double d1) throws EvaluationException;
- }
- public static abstract class MultiArg extends NumericFunction {
- private final int _minArgs;
- private final int _maxArgs;
- protected MultiArg(int minArgs, int maxArgs) {
- _minArgs = minArgs;
- _maxArgs = maxArgs;
- }
- protected final double eval(ValueEval[] args, int srcCellRow, int srcCellCol) throws EvaluationException {
- int nArgs = args.length;
- if (nArgs < _minArgs || nArgs > _maxArgs) {
- throw new EvaluationException(ErrorEval.VALUE_INVALID);
+
+ public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
+ double result;
+ try {
+ double d0 = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+ double d1 = singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+ result = evaluate(d0, d1);
+ checkValue(result);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
}
- double[] ds = new double[nArgs];
- for(int i=0; i