diff --git a/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java b/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java
index dd9ecc2af..f7ea76a36 100644
--- a/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java
@@ -61,9 +61,6 @@ final class ParityFunction implements FreeRefFunction {
private static int evaluateArgParity(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
- if (ve == BlankEval.INSTANCE) {
- return 0;
- }
double d = OperandResolver.coerceValueToDouble(ve);
if (d < 0) {
d = -d;
diff --git a/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java b/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java
index ac196723e..005599d45 100644
--- a/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java
+++ b/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java
@@ -97,9 +97,6 @@ final class YearFrac implements FreeRefFunction {
Calendar date = parseDate(strVal);
return HSSFDateUtil.getExcelDate(date, false);
}
- if (ve instanceof BlankEval) {
- return 0.0;
- }
return OperandResolver.coerceValueToDouble(ve);
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java b/src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java
index 627b26998..87f45236b 100755
--- a/src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java
@@ -171,7 +171,8 @@ public final class OperandResolver {
/**
* Applies some conversion rules if the supplied value is not already an integer.
- * Value is first coerced to a double ( See coerceValueToDouble() ).
+ * Value is first coerced to a double ( See coerceValueToDouble() ).
+ * Note - BlankEval is converted to 0
.
*
* Excel typically converts doubles to integers by truncating toward negative infinity.
* The equivalent java code is:
@@ -181,6 +182,9 @@ public final class OperandResolver {
*
*/
public static int coerceValueToInt(ValueEval ev) throws EvaluationException {
+ if (ev == BlankEval.INSTANCE) {
+ return 0;
+ }
double d = coerceValueToDouble(ev);
// Note - the standard java type conversion from double to int truncates toward zero.
// but Math.floor() truncates toward negative infinity
@@ -189,16 +193,20 @@ public final class OperandResolver {
/**
* Applies some conversion rules if the supplied value is not already a number.
- * Note - BlankEval is not supported and must be handled by the caller.
- * @param ev must be a NumberEval, StringEval or BoolEval
+ * Note - BlankEval is converted to {@link NumberEval#ZERO}.
+ * @param ev must be a {@link NumberEval}, {@link StringEval}, {@link BoolEval} or
+ * {@link BlankEval}
* @return actual, parsed or interpreted double value (respectively).
* @throws EvaluationException(#VALUE!) only if a StringEval is supplied and cannot be parsed
* as a double (See parseDouble() for allowable formats).
- * @throws RuntimeException if the supplied parameter is not NumberEval,
- * StringEval or BoolEval
+ * @throws RuntimeException if the supplied parameter is not {@link NumberEval},
+ * {@link StringEval}, {@link BoolEval} or {@link BlankEval}
*/
public static double coerceValueToDouble(ValueEval ev) throws EvaluationException {
+ if (ev == BlankEval.INSTANCE) {
+ return 0.0;
+ }
if (ev instanceof NumericValueEval) {
// this also handles booleans
return ((NumericValueEval)ev).getNumberValue();
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/PercentEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/PercentEval.java
index d03e44745..d8a579c42 100755
--- a/src/java/org/apache/poi/hssf/record/formula/eval/PercentEval.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/PercentEval.java
@@ -33,12 +33,9 @@ public final class PercentEval implements OperationEval {
if (args.length != 1) {
return ErrorEval.VALUE_INVALID;
}
- double d0;
+ double d0;
try {
ValueEval ve = OperandResolver.getSingleValue(args[0], srcRow, srcCol);
- if (ve instanceof BlankEval) {
- return NumberEval.ZERO;
- }
d0 = OperandResolver.coerceValueToDouble(ve);
} catch (EvaluationException e) {
return e.getErrorEval();
@@ -50,7 +47,7 @@ public final class PercentEval implements OperationEval {
return 1;
}
public final int getType() {
- // TODO - remove
- throw new RuntimeException("obsolete code should not be called");
- }
+ // TODO - remove
+ throw new RuntimeException("obsolete code should not be called");
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/TwoOperandNumericOperation.java b/src/java/org/apache/poi/hssf/record/formula/eval/TwoOperandNumericOperation.java
index 665ba4b46..0f2933fae 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/TwoOperandNumericOperation.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/TwoOperandNumericOperation.java
@@ -23,18 +23,15 @@ package org.apache.poi.hssf.record.formula.eval;
abstract class TwoOperandNumericOperation implements OperationEval {
public final int getType() {
- // TODO - remove
- throw new RuntimeException("obsolete code should not be called");
- }
- protected final double singleOperandEvaluate(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
- ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
- if (ve instanceof BlankEval) {
- return 0.0;
- }
- return OperandResolver.coerceValueToDouble(ve);
- }
-
- public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+ // TODO - remove
+ throw new RuntimeException("obsolete code should not be called");
+ }
+ protected final double singleOperandEvaluate(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
+ ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+ return OperandResolver.coerceValueToDouble(ve);
+ }
+
+ public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
double result;
try {
double d0 = singleOperandEvaluate(args[0], srcCellRow, srcCellCol);
@@ -46,8 +43,8 @@ abstract class TwoOperandNumericOperation implements OperationEval {
} catch (EvaluationException e) {
return e.getErrorEval();
}
- return new NumberEval(result);
- }
+ return new NumberEval(result);
+ }
protected abstract double evaluate(double d0, double d1) throws EvaluationException;
public final int getNumberOfOperands() {
return 2;
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/UnaryMinusEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/UnaryMinusEval.java
index 8174429e0..780334ae8 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/UnaryMinusEval.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/UnaryMinusEval.java
@@ -33,12 +33,9 @@ public final class UnaryMinusEval implements OperationEval {
if (args.length != 1) {
return ErrorEval.VALUE_INVALID;
}
- double d;
+ double d;
try {
ValueEval ve = OperandResolver.getSingleValue(args[0], srcRow, srcCol);
- if (ve instanceof BlankEval) {
- return NumberEval.ZERO;
- }
d = OperandResolver.coerceValueToDouble(ve);
} catch (EvaluationException e) {
return e.getErrorEval();
@@ -50,7 +47,7 @@ public final class UnaryMinusEval implements OperationEval {
return 1;
}
public final int getType() {
- // TODO - remove
- throw new RuntimeException("obsolete code should not be called");
- }
+ // TODO - remove
+ throw new RuntimeException("obsolete code should not be called");
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/UnaryPlusEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/UnaryPlusEval.java
index 66c5f6801..831d34286 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/UnaryPlusEval.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/UnaryPlusEval.java
@@ -24,21 +24,18 @@ package org.apache.poi.hssf.record.formula.eval;
*/
public final class UnaryPlusEval implements OperationEval {
- public static final OperationEval instance = new UnaryPlusEval();
-
- private UnaryPlusEval() {
- }
+ public static final OperationEval instance = new UnaryPlusEval();
+
+ private UnaryPlusEval() {
+ }
- public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
- if(args.length != 1) {
- return ErrorEval.VALUE_INVALID;
- }
- double d;
+ public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+ if(args.length != 1) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ double d;
try {
ValueEval ve = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
- if(ve instanceof BlankEval) {
- return NumberEval.ZERO;
- }
if(ve instanceof StringEval) {
// Note - asymmetric with UnaryMinus
// -"hello" evaluates to #VALUE!
@@ -49,14 +46,14 @@ public final class UnaryPlusEval implements OperationEval {
} catch (EvaluationException e) {
return e.getErrorEval();
}
- return new NumberEval(+d);
- }
+ return new NumberEval(+d);
+ }
- public int getNumberOfOperands() {
- return 1;
- }
+ public int getNumberOfOperands() {
+ return 1;
+ }
- public int getType() {
- throw new RuntimeException("obsolete code should not be called");
- }
+ public int getType() {
+ throw new RuntimeException("obsolete code should not be called");
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/CalendarFieldFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/CalendarFieldFunction.java
index 3df7c9c5d..b1ea02fdc 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/CalendarFieldFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/CalendarFieldFunction.java
@@ -21,7 +21,6 @@ import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
-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.EvaluationException;
@@ -58,12 +57,7 @@ public final class CalendarFieldFunction implements Function {
int val;
try {
ValueEval ve = OperandResolver.getSingleValue(operands[0], srcCellRow, srcCellCol);
-
- if (ve == BlankEval.INSTANCE) {
- val = 0;
- } else {
- val = OperandResolver.coerceValueToInt(ve);
- }
+ val = OperandResolver.coerceValueToInt(ve);
} catch (EvaluationException e) {
return e.getErrorEval();
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java b/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java
index ee67ef8ec..613a3d144 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java
@@ -339,23 +339,19 @@ final class LookupUtils {
throw EvaluationException.invalidRef();
}
int oneBasedIndex;
- if(veRowColIndexArg instanceof BlankEval) {
- oneBasedIndex = 0;
- } else {
- if(veRowColIndexArg instanceof StringEval) {
- StringEval se = (StringEval) veRowColIndexArg;
- String strVal = se.getStringValue();
- Double dVal = OperandResolver.parseDouble(strVal);
- if(dVal == null) {
- // String does not resolve to a number. Raise #REF! error.
- throw EvaluationException.invalidRef();
- // This includes text booleans "TRUE" and "FALSE". They are not valid.
- }
- // else - numeric value parses OK
+ if(veRowColIndexArg instanceof StringEval) {
+ StringEval se = (StringEval) veRowColIndexArg;
+ String strVal = se.getStringValue();
+ Double dVal = OperandResolver.parseDouble(strVal);
+ if(dVal == null) {
+ // String does not resolve to a number. Raise #REF! error.
+ throw EvaluationException.invalidRef();
+ // This includes text booleans "TRUE" and "FALSE". They are not valid.
}
- // actual BoolEval values get interpreted as FALSE->0 and TRUE->1
- oneBasedIndex = OperandResolver.coerceValueToInt(veRowColIndexArg);
+ // else - numeric value parses OK
}
+ // actual BoolEval values get interpreted as FALSE->0 and TRUE->1
+ oneBasedIndex = OperandResolver.coerceValueToInt(veRowColIndexArg);
if (oneBasedIndex < 1) {
// note this is asymmetric with the errors when the index is too large (#REF!)
throw EvaluationException.invalidValue();
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Mid.java b/src/java/org/apache/poi/hssf/record/formula/functions/Mid.java
index 7f30aa4ce..b9d679d3d 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Mid.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Mid.java
@@ -17,7 +17,6 @@
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.EvaluationException;
@@ -81,12 +80,8 @@ public class Mid implements Function {
private static int evaluateNumberArg(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
ValueEval ev = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
- if (ev instanceof BlankEval) {
- // Note - for start_num arg, blank causes error(#VALUE!),
- // but for num_chars causes empty string to be returned.
- return 0;
- }
-
+ // Note - for start_num arg, blank/zero causes error(#VALUE!),
+ // but for num_chars causes empty string to be returned.
return OperandResolver.coerceValueToInt(ev);
}
}
\ No newline at end of file
diff --git a/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls b/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls
index 68a12d834..e4c8e42dc 100644
Binary files a/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls and b/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/data/externalFunctionExample.xls b/src/testcases/org/apache/poi/hssf/data/externalFunctionExample.xls
index fc81e60a1..b8dabbf71 100755
Binary files a/src/testcases/org/apache/poi/hssf/data/externalFunctionExample.xls and b/src/testcases/org/apache/poi/hssf/data/externalFunctionExample.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java b/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java
index b3a82c6de..dbfc8269d 100755
--- a/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java
@@ -77,8 +77,9 @@ public final class TestExternalFunctionFormulas extends TestCase {
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
confirmCellEval(sheet, 0, 0, fe, "YEARFRAC(B1,C1)", 29.0/90.0);
confirmCellEval(sheet, 1, 0, fe, "YEARFRAC(B2,C2)", 0.0);
- confirmCellEval(sheet, 2, 0, fe, "IF(ISEVEN(3),1.2,1.6)", 1.6);
- confirmCellEval(sheet, 3, 0, fe, "IF(ISODD(3),1.2,1.6)", 1.2);
+ confirmCellEval(sheet, 2, 0, fe, "YEARFRAC(B3,C3,D3)", 0.0);
+ confirmCellEval(sheet, 3, 0, fe, "IF(ISEVEN(3),1.2,1.6)", 1.6);
+ confirmCellEval(sheet, 4, 0, fe, "IF(ISODD(3),1.2,1.6)", 1.2);
}
private static void confirmCellEval(HSSFSheet sheet, int rowIx, int colIx,