diff --git a/main/SS/Formula/Eval/FunctionEval.cs b/main/SS/Formula/Eval/FunctionEval.cs
index 6c79df50b..626960612 100644
--- a/main/SS/Formula/Eval/FunctionEval.cs
+++ b/main/SS/Formula/Eval/FunctionEval.cs
@@ -137,14 +137,14 @@ private static Function[] ProduceFunctions()
retval[37] = new Or(); // OR
retval[38] = new Not(); // NOT
retval[39] = NumericFunction.MOD; // MOD
- retval[40] = new NotImplementedFunction("DCOUNT"); // DCOUNT
- retval[41] = new NotImplementedFunction("DSUM"); // DSUM
- retval[42] = new NotImplementedFunction("DAVERAGE"); // DAVERAGE
+ retval[40] = new DStarRunner(DStarRunner.DStarAlgorithmEnum.DCOUNT); // DCOUNT
+ retval[41] = new DStarRunner(DStarRunner.DStarAlgorithmEnum.DSUM); // DSUM
+ retval[42] = new DStarRunner(DStarRunner.DStarAlgorithmEnum.DAVERAGE); // DAVERAGE
retval[43] = new DStarRunner(DStarRunner.DStarAlgorithmEnum.DMIN); // DMIN
- retval[44] = new NotImplementedFunction("DMAX"); // DMAX
- retval[45] = new NotImplementedFunction("DSTDEV"); // DSTDEV
+ retval[44] = new DStarRunner(DStarRunner.DStarAlgorithmEnum.DMAX);// DMAX
+ retval[45] = new DStarRunner(DStarRunner.DStarAlgorithmEnum.DSTDEV); // DSTDEV
retval[46] = AggregateFunction.VAR; // VAR
- retval[47] = new NotImplementedFunction("DVAR"); // DVAR
+ retval[47] = new DStarRunner(DStarRunner.DStarAlgorithmEnum.DVAR);
retval[48] = TextFunction.TEXT; // TEXT
retval[49] = new NotImplementedFunction("LINEST"); // LINEST
retval[50] = new NotImplementedFunction("TREND"); // TREND
@@ -281,17 +281,17 @@ private static Function[] ProduceFunctions()
retval[186] = new NotImplementedFunction("GetWORKSPACE"); // GetWORKSPACE
retval[187] = new NotImplementedFunction("GetWINDOW"); // GetWINDOW
retval[188] = new NotImplementedFunction("GetDOCUMENT"); // GetDOCUMENT
- retval[189] = new NotImplementedFunction("DPRODUCT"); // DPRODUCT
+ retval[189] = new DStarRunner(DStarRunner.DStarAlgorithmEnum.DPRODUCT);
retval[190] = LogicalFunction.ISNONTEXT; // IsNONTEXT
retval[191] = new NotImplementedFunction("GetNOTE"); // GetNOTE
retval[192] = new NotImplementedFunction("NOTE"); // NOTE
- retval[193] = new NotImplementedFunction("STDEVP"); // STDEVP
+ retval[193] = AggregateFunction.STDEVP;
retval[194] = AggregateFunction.VARP; // VARP
- retval[195] = new NotImplementedFunction("DSTDEVP"); // DSTDEVP
- retval[196] = new NotImplementedFunction("DVARP"); // DVARP
+ retval[195] = new DStarRunner(DStarRunner.DStarAlgorithmEnum.DSTDEVP);
+ retval[196] = new DStarRunner(DStarRunner.DStarAlgorithmEnum.DVARP);
retval[197] = NumericFunction.TRUNC; // TRUNC
retval[198] = LogicalFunction.ISLOGICAL; // IsLOGICAL
- retval[199] = new NotImplementedFunction("DCOUNTA"); // DCOUNTA
+ retval[199] = new DStarRunner(DStarRunner.DStarAlgorithmEnum.DCOUNTA);
retval[200] = new NotImplementedFunction("DELETEBAR"); // DELETEBAR
retval[201] = new NotImplementedFunction("UNREGISTER"); // UNREGISTER
retval[204] = NumericFunction.DOLLAR; // USDOLLAR
diff --git a/main/SS/Formula/Functions/DAverage.cs b/main/SS/Formula/Functions/DAverage.cs
new file mode 100644
index 000000000..4756cf10f
--- /dev/null
+++ b/main/SS/Formula/Functions/DAverage.cs
@@ -0,0 +1,63 @@
+/* ====================================================================
+ 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.
+==================================================================== */
+
+namespace NPOI.SS.Formula.Functions
+{
+ using ExtendedNumerics;
+ using NPOI.SS.Formula.Eval;
+ using System.Numerics;
+
+ ///
+ /// Implementation of the DAverage function:
+ /// Gets the average value of a column in an area with given conditions.
+ ///
+ public sealed class DAverage : IDStarAlgorithm
+ {
+ private long count;
+ private double total;
+ public bool ProcessMatch(ValueEval eval)
+ {
+ if(eval is NumericValueEval)
+ {
+ count++;
+ total += ((NumericValueEval) eval).NumberValue;
+ }
+ return true;
+ }
+ public ValueEval Result
+ {
+ get
+ {
+ return count == 0 ? NumberEval.ZERO : new NumberEval(GetAverage());
+ }
+ }
+
+ private double GetAverage()
+ {
+ return Divide(total, count);
+ }
+
+ private static double Divide(double total, long count)
+ {
+ return (double) BigDecimal.Divide(new BigDecimal(total), new BigInteger(count));
+ }
+
+ public bool AllowEmptyMatchField { get; } = false;
+ }
+}
+
+
diff --git a/main/SS/Formula/Functions/DCount.cs b/main/SS/Formula/Functions/DCount.cs
new file mode 100644
index 000000000..518036b31
--- /dev/null
+++ b/main/SS/Formula/Functions/DCount.cs
@@ -0,0 +1,54 @@
+/* ====================================================================
+ 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.
+==================================================================== */
+
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace NPOI.SS.Formula.Functions
+{
+ using NPOI.SS.Formula.Eval;
+
+ ///
+ /// Implementation of the DCount function:
+ /// Counts the number of numeric cells in a column in an area with given conditions.
+ ///
+ public sealed class DCount : IDStarAlgorithm
+ {
+ private long count;
+ public bool ProcessMatch(ValueEval eval)
+ {
+ if(eval is NumericValueEval)
+ {
+ count++;
+ }
+ return true;
+ }
+ public ValueEval Result
+ {
+ get
+ {
+ return new NumberEval(count);
+ }
+ }
+ public bool AllowEmptyMatchField { get; } = true;
+ }
+}
+
diff --git a/main/SS/Formula/Functions/DCountA.cs b/main/SS/Formula/Functions/DCountA.cs
new file mode 100644
index 000000000..ca777d42b
--- /dev/null
+++ b/main/SS/Formula/Functions/DCountA.cs
@@ -0,0 +1,55 @@
+/* ====================================================================
+ 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.
+==================================================================== */
+
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace NPOI.SS.Formula.Functions
+{
+ using NPOI.SS.Formula.Eval;
+
+ ///
+ /// Implementation of the DCountA function:
+ /// Counts the number of non-blank cells in a column in an area with given conditions.
+ ///
+ public sealed class DCountA : IDStarAlgorithm
+ {
+ private long count;
+ public bool ProcessMatch(ValueEval eval)
+ {
+ if(!(eval is BlankEval))
+ {
+ count++;
+ }
+ return true;
+ }
+
+ public ValueEval Result
+ {
+ get
+ {
+ return new NumberEval(count);
+ }
+ }
+ public bool AllowEmptyMatchField { get; } = true;
+ }
+}
+
diff --git a/main/SS/Formula/Functions/DGet.cs b/main/SS/Formula/Functions/DGet.cs
index 25c66546e..dea3e25d2 100644
--- a/main/SS/Formula/Functions/DGet.cs
+++ b/main/SS/Formula/Functions/DGet.cs
@@ -33,14 +33,25 @@ public class DGet : IDStarAlgorithm
public bool ProcessMatch(ValueEval eval)
{
- if (result == null) // First match, just Set the value.
+ if(result == null) // First match, just Set the value.
{
result = eval;
}
else // There was a previous match, since there is only exactly one allowed, bail out1.
{
- result = ErrorEval.NUM_ERROR;
- return false;
+ if(result is BlankEval)
+ {
+ result = eval;
+ }
+ else
+ {
+ // We have a previous filled result.
+ if(!(eval is BlankEval))
+ {
+ result = ErrorEval.NUM_ERROR;
+ return false;
+ }
+ }
}
return true;
@@ -50,17 +61,18 @@ public ValueEval Result
{
get
{
- if (result == null)
+ if(result == null)
{
return ErrorEval.VALUE_INVALID;
}
- if (result is BlankEval) {
+ if(result is BlankEval)
+ {
return ErrorEval.VALUE_INVALID;
}
else
try
{
- if (OperandResolver.CoerceValueToString(OperandResolver.GetSingleValue(result, 0, 0)).Equals(""))
+ if(OperandResolver.CoerceValueToString(OperandResolver.GetSingleValue(result, 0, 0)).Equals(""))
{
return ErrorEval.VALUE_INVALID;
}
@@ -69,12 +81,14 @@ public ValueEval Result
return result;
}
}
- catch (EvaluationException e)
+ catch(EvaluationException e)
{
return e.GetErrorEval();
}
}
}
+
+ public bool AllowEmptyMatchField { get; } = false;
}
}
diff --git a/main/SS/Formula/Functions/DMax.cs b/main/SS/Formula/Functions/DMax.cs
new file mode 100644
index 000000000..88931bd09
--- /dev/null
+++ b/main/SS/Formula/Functions/DMax.cs
@@ -0,0 +1,85 @@
+/* ====================================================================
+ 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.
+==================================================================== */
+
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace NPOI.SS.Formula.Functions
+{
+ using NPOI.SS.Formula.Eval;
+
+
+
+
+ ///
+ ///
+ /// Implementation of the DMax function:
+ /// Finds the maximum value of a column in an area with given conditions.
+ ///
+ ///
+ /// TODO:
+ /// - functions as conditions
+ ///
+ ///
+ public sealed class DMax : IDStarAlgorithm
+ {
+ private ValueEval maximumValue;
+ public bool ProcessMatch(ValueEval eval)
+ {
+ if(eval is NumericValueEval)
+ {
+ if(maximumValue == null)
+ { // First match, just Set the value.
+ maximumValue = eval;
+ }
+ else
+ { // There was a previous match, find the new minimum.
+ double currentValue = ((NumericValueEval)eval).NumberValue;
+ double oldValue = ((NumericValueEval)maximumValue).NumberValue;
+ if(currentValue > oldValue)
+ {
+ maximumValue = eval;
+ }
+ }
+ }
+
+ return true;
+ }
+ public ValueEval Result
+ {
+ get
+ {
+ if(maximumValue == null)
+ {
+ return NumberEval.ZERO;
+ }
+ else
+ {
+ return maximumValue;
+ }
+ }
+
+ }
+ public bool AllowEmptyMatchField { get; } = false;
+ }
+}
+
+
diff --git a/main/SS/Formula/Functions/DMin.cs b/main/SS/Formula/Functions/DMin.cs
index b568ca02d..6083d525a 100644
--- a/main/SS/Formula/Functions/DMin.cs
+++ b/main/SS/Formula/Functions/DMin.cs
@@ -67,6 +67,8 @@ public ValueEval Result
}
}
}
+
+ public bool AllowEmptyMatchField { get; } = false;
}
}
\ No newline at end of file
diff --git a/main/SS/Formula/Functions/DProduct.cs b/main/SS/Formula/Functions/DProduct.cs
new file mode 100644
index 000000000..c471c4e4f
--- /dev/null
+++ b/main/SS/Formula/Functions/DProduct.cs
@@ -0,0 +1,65 @@
+/* ====================================================================
+ 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.
+==================================================================== */
+
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace NPOI.SS.Formula.Functions
+{
+ using NPOI.SS.Formula.Eval;
+
+ ///
+ /// Implementation of the DProduct function:
+ /// Gets the product value of a column in an area with given conditions.
+ ///
+ public sealed class DProduct : IDStarAlgorithm
+ {
+ private double product;
+ private bool initDone = false;
+ public bool ProcessMatch(ValueEval eval)
+ {
+ if(eval is NumericValueEval)
+ {
+ if(initDone)
+ {
+ product *= ((NumericValueEval) eval).NumberValue;
+ }
+ else
+ {
+ product = ((NumericValueEval) eval).NumberValue;
+ initDone = true;
+ }
+ }
+ return true;
+ }
+ public ValueEval Result
+ {
+ get
+ {
+ return new NumberEval(product);
+ }
+ }
+
+ public bool AllowEmptyMatchField { get; } = false;
+ }
+}
+
+
diff --git a/main/SS/Formula/Functions/DStarRunner.cs b/main/SS/Formula/Functions/DStarRunner.cs
index 8d39ce165..84d0d0cab 100644
--- a/main/SS/Formula/Functions/DStarRunner.cs
+++ b/main/SS/Formula/Functions/DStarRunner.cs
@@ -18,7 +18,7 @@ limitations under the License.
namespace NPOI.SS.Formula.Functions
{
using System;
-
+ using System.Text.RegularExpressions;
using NPOI.SS.Formula;
using NPOI.SS.Formula.Eval;
using NPOI.SS.Util;
@@ -36,7 +36,16 @@ public enum DStarAlgorithmEnum
{
DGET,
DMIN,
- // DMAX, // DMAX is not yet implemented
+ DMAX,
+ DSUM,
+ DCOUNT,
+ DCOUNTA,
+ DAVERAGE,
+ DSTDEV,
+ DSTDEVP,
+ DVAR,
+ DVARP,
+ DPRODUCT,
}
private DStarAlgorithmEnum algoType;
@@ -69,6 +78,50 @@ public ValueEval Evaluate(int srcRowIndex, int srcColumnIndex,
AreaEval db = (AreaEval)database;
AreaEval cdb = (AreaEval)conditionDatabase;
+ // Create an algorithm runner.
+ IDStarAlgorithm algorithm = null;
+ switch(algoType)
+ {
+ case DStarAlgorithmEnum.DGET:
+ algorithm = new DGet();
+ break;
+ case DStarAlgorithmEnum.DMIN:
+ algorithm = new DMin();
+ break;
+ case DStarAlgorithmEnum.DMAX:
+ algorithm = new DMax();
+ break;
+ case DStarAlgorithmEnum.DSUM:
+ algorithm = new DSum();
+ break;
+ case DStarAlgorithmEnum.DCOUNT:
+ algorithm = new DCount();
+ break;
+ case DStarAlgorithmEnum.DCOUNTA:
+ algorithm = new DCountA();
+ break;
+ case DStarAlgorithmEnum.DAVERAGE:
+ algorithm = new DAverage();
+ break;
+ case DStarAlgorithmEnum.DSTDEV:
+ algorithm = new DStdev();
+ break;
+ case DStarAlgorithmEnum.DSTDEVP:
+ algorithm = new DStdevp();
+ break;
+ case DStarAlgorithmEnum.DVAR:
+ algorithm = new DVar();
+ break;
+ case DStarAlgorithmEnum.DVARP:
+ algorithm = new DVarp();
+ break;
+ case DStarAlgorithmEnum.DPRODUCT:
+ algorithm = new DProduct();
+ break;
+ default:
+ throw new InvalidOperationException("Unexpected algorithm type " + algoType + " encountered.");
+ }
+
try
{
filterColumn = OperandResolver.GetSingleValue(filterColumn, srcRowIndex, srcColumnIndex);
@@ -81,26 +134,24 @@ public ValueEval Evaluate(int srcRowIndex, int srcColumnIndex,
int fc;
try
{
- fc = GetColumnForName(filterColumn, db);
+ if(filterColumn is NumericValueEval)
+ {
+ //fc is zero based while Excel uses 1 based column numbering
+ fc = (int) Math.Round(((NumericValueEval) filterColumn).NumberValue) - 1;
+ }
+ else
+ fc = GetColumnForName(filterColumn, db);
}
catch (EvaluationException)
{
return ErrorEval.VALUE_INVALID;
}
- if (fc == -1)
+ if (fc == -1 && !algorithm.AllowEmptyMatchField)
{ // column not found
return ErrorEval.VALUE_INVALID;
}
- // Create an algorithm runner.
- IDStarAlgorithm algorithm = null;
- switch (algoType)
- {
- case DStarAlgorithmEnum.DGET: algorithm = new DGet(); break;
- case DStarAlgorithmEnum.DMIN: algorithm = new DMin(); break;
- default:
- throw new InvalidOperationException("Unexpected algorithm type " + algoType + " encountered.");
- }
+
// Iterate over all db entries.
int height = db.Height;
@@ -119,6 +170,10 @@ public ValueEval Evaluate(int srcRowIndex, int srcColumnIndex,
if (matches)
{
ValueEval currentValueEval = ResolveReference(db, row, fc);
+ if(fc < 0 && algorithm.AllowEmptyMatchField && !(currentValueEval is NumericValueEval))
+ {
+ currentValueEval = NumberEval.ZERO;
+ }
// Pass the match to the algorithm and conditionally abort the search.
bool shouldContinue = algorithm.ProcessMatch(currentValueEval);
if (!shouldContinue)
@@ -138,7 +193,8 @@ private enum Operator
largerEqualThan,
smallerThan,
smallerEqualThan,
- equal
+ equal,
+ notEqual,
}
/**
@@ -179,7 +235,7 @@ private static int GetColumnForString(AreaEval db, String name)
continue;
}
String columnName = OperandResolver.CoerceValueToString(columnNameValueEval);
- if (name.Equals(columnName))
+ if (name.Equals(columnName, StringComparison.OrdinalIgnoreCase))
{
resultColumn = column;
break;
@@ -278,11 +334,24 @@ private static bool testNormalCondition(ValueEval value, ValueEval condition)
if (conditionString.StartsWith("<"))
{ // It's a <= condition.
String number = conditionString.Substring(1);
- if (number.StartsWith("="))
+ if(number.StartsWith("="))
{
number = number.Substring(1);
return testNumericCondition(value, Operator.smallerEqualThan, number);
}
+ else if(number.StartsWith(">"))
+ {
+ number = number.Substring(1);
+ bool itsANumber = IsNumber(number);
+ if(itsANumber)
+ {
+ return testNumericCondition(value, Operator.notEqual, number);
+ }
+ else
+ {
+ return testStringCondition(value, Operator.notEqual, number);
+ }
+ }
else
{
return testNumericCondition(value, Operator.smallerThan, number);
@@ -310,32 +379,14 @@ private static bool testNormalCondition(ValueEval value, ValueEval condition)
return value is BlankEval;
}
// Distinguish between string and number.
- bool itsANumber = false;
- try
- {
- int.Parse(stringOrNumber);
- itsANumber = true;
- }
- catch (FormatException)
- { // It's not an int.
- try
- {
- Double.Parse(stringOrNumber);
- itsANumber = true;
- }
- catch (FormatException)
- { // It's a string.
- itsANumber = false;
- }
- }
+ bool itsANumber = IsNumber(stringOrNumber);
if (itsANumber)
{
return testNumericCondition(value, Operator.equal, stringOrNumber);
}
else
{ // It's a string.
- String valueString = value is BlankEval ? "" : OperandResolver.CoerceValueToString(value);
- return stringOrNumber.Equals(valueString);
+ return testStringCondition(value, Operator.equal, stringOrNumber);
}
}
else
@@ -347,7 +398,17 @@ private static bool testNormalCondition(ValueEval value, ValueEval condition)
else
{
String valueString = value is BlankEval ? "" : OperandResolver.CoerceValueToString(value);
- return valueString.StartsWith(conditionString);
+ String lowerValue = valueString.ToLower(LocaleUtil.GetUserLocale());
+ String lowerCondition = conditionString.ToLower(LocaleUtil.GetUserLocale());
+ Regex pattern = Countif.StringMatcher.GetWildCardPattern(lowerCondition);
+ if(pattern == null)
+ {
+ return lowerValue.StartsWith(lowerCondition);
+ }
+ else
+ {
+ return pattern.IsMatch(lowerValue);
+ }
}
}
}
@@ -423,6 +484,30 @@ private static bool testNumericCondition(
return result <= 0;
case Operator.equal:
return result == 0;
+ case Operator.notEqual:
+ return result != 0;
+ }
+ return false; // Can not be reached.
+ }
+
+ /**
+ * Test whether a value matches a text condition.
+ * @param valueEval Value to check.
+ * @param op Comparator to use.
+ * @param condition Value to check against.
+ * @return whether the condition holds.
+ */
+ private static bool testStringCondition(
+ ValueEval valueEval, Operator op, String condition)
+ {
+
+ String valueString = valueEval is BlankEval ? "" : OperandResolver.CoerceValueToString(valueEval);
+ switch(op)
+ {
+ case Operator.equal:
+ return valueString.Equals(condition, StringComparison.OrdinalIgnoreCase);
+ case Operator.notEqual:
+ return !valueString.Equals(condition, StringComparison.OrdinalIgnoreCase);
}
return false; // Can not be reached.
}
@@ -469,6 +554,36 @@ private static ValueEval ResolveReference(AreaEval db, int dbRow, int dbCol)
return e.GetErrorEval();
}
}
+
+ /**
+ * Determines whether a given string represents a valid number.
+ *
+ * @param value The string to be checked if it represents a number.
+ * @return {@code true} if the string can be parsed as either an integer or
+ * a double; {@code false} otherwise.
+ */
+ private static bool IsNumber(String value)
+ {
+ bool itsANumber;
+ try
+ {
+ int.Parse(value);
+ itsANumber = true;
+ }
+ catch(FormatException)
+ { // It's not an int.
+ try
+ {
+ double.Parse(value);
+ itsANumber = true;
+ }
+ catch(FormatException)
+ { // It's a string.
+ itsANumber = false;
+ }
+ }
+ return itsANumber;
+ }
}
}
\ No newline at end of file
diff --git a/main/SS/Formula/Functions/DStdev.cs b/main/SS/Formula/Functions/DStdev.cs
new file mode 100644
index 000000000..49cac5406
--- /dev/null
+++ b/main/SS/Formula/Functions/DStdev.cs
@@ -0,0 +1,64 @@
+/* ====================================================================
+ 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.
+==================================================================== */
+
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace NPOI.SS.Formula.Functions
+{
+ using ExtendedNumerics;
+ using NPOI.SS.Formula.Eval;
+ using NPOI.SS.Util;
+ ///
+ /// Implementation of the DStdev function:
+ /// Gets the standard deviation value of a column in an area with given conditions.
+ ///
+ public sealed class DStdev : IDStarAlgorithm
+ {
+ private List values = new List();
+ public bool ProcessMatch(ValueEval eval)
+ {
+ if(eval is NumericValueEval)
+ {
+ values.Add((NumericValueEval) eval);
+ }
+ return true;
+ }
+ public ValueEval Result
+ {
+ get
+ {
+ double[] array = new double[values.Count];
+ int pos = 0;
+ foreach(NumericValueEval d in values)
+ {
+ array[pos++] = d.NumberValue;
+ }
+ double stdev = StatsLib.stdev(array);
+ return new NumberEval((double) BigDecimal.Parse(NumberToTextConverter.ToText(stdev)));
+
+ }
+ }
+ public bool AllowEmptyMatchField { get; } = false;
+ }
+}
+
+
diff --git a/main/SS/Formula/Functions/DStdevp.cs b/main/SS/Formula/Functions/DStdevp.cs
new file mode 100644
index 000000000..c951adad7
--- /dev/null
+++ b/main/SS/Formula/Functions/DStdevp.cs
@@ -0,0 +1,63 @@
+/* ====================================================================
+ 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.
+==================================================================== */
+
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace NPOI.SS.Formula.Functions
+{
+ using ExtendedNumerics;
+ using NPOI.SS.Formula.Eval;
+ using NPOI.SS.Util;
+ ///
+ /// Implementation of the DStdevp function:
+ /// Gets the standard deviation value of a column in an area with given conditions.
+ ///
+ public sealed class DStdevp : IDStarAlgorithm
+ {
+ private List values = new List();
+ public bool ProcessMatch(ValueEval eval)
+ {
+ if(eval is NumericValueEval)
+ {
+ values.Add((NumericValueEval) eval);
+ }
+ return true;
+ }
+ public ValueEval Result
+ {
+ get
+ {
+ double[] array = new double[values.Count];
+ int pos = 0;
+ foreach(NumericValueEval d in values)
+ {
+ array[pos++] = d.NumberValue;
+ }
+ double stdev = StatsLib.stdevp(array);
+ return new NumberEval((double)BigDecimal.Parse(NumberToTextConverter.ToText(stdev)));
+ }
+
+ }
+
+ public bool AllowEmptyMatchField { get; } = false;
+ }
+}
diff --git a/main/SS/Formula/Functions/DSum.cs b/main/SS/Formula/Functions/DSum.cs
new file mode 100644
index 000000000..f6cd3a2c0
--- /dev/null
+++ b/main/SS/Formula/Functions/DSum.cs
@@ -0,0 +1,67 @@
+/* ====================================================================
+ 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.
+==================================================================== */
+
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace NPOI.SS.Formula.Functions
+{
+ using NPOI.SS.Formula.Eval;
+
+
+
+
+ ///
+ ///
+ /// Implementation of the DSum function:
+ /// Finds the total value of matching values in a column in an area with given conditions.
+ ///
+ ///
+ /// TODO:
+ /// - functions as conditions
+ ///
+ ///
+ public sealed class DSum : IDStarAlgorithm
+ {
+ private double totalValue = 0;
+ public bool ProcessMatch(ValueEval eval)
+ {
+ if(eval is NumericValueEval)
+ {
+ double currentValue = ((NumericValueEval)eval).NumberValue;
+ totalValue += currentValue;
+ }
+
+ return true;
+ }
+ public ValueEval Result
+ {
+ get
+ {
+ return new NumberEval(totalValue);
+ }
+ }
+
+ public bool AllowEmptyMatchField { get; } = false;
+ }
+}
+
+
diff --git a/main/SS/Formula/Functions/DVar.cs b/main/SS/Formula/Functions/DVar.cs
new file mode 100644
index 000000000..6adfe6ac2
--- /dev/null
+++ b/main/SS/Formula/Functions/DVar.cs
@@ -0,0 +1,59 @@
+/* ====================================================================
+ 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.
+==================================================================== */
+
+using System.Collections.Generic;
+
+namespace NPOI.SS.Formula.Functions
+{
+ using ExtendedNumerics;
+ using NPOI.SS.Formula.Eval;
+ using NPOI.SS.Util;
+ ///
+ /// Implementation of the DVar function:
+ /// Gets the variance value of a column in an area with given conditions.
+ ///
+ public sealed class DVar : IDStarAlgorithm
+ {
+ private List values = new List();
+ public bool ProcessMatch(ValueEval eval)
+ {
+ if(eval is NumericValueEval)
+ {
+ values.Add((NumericValueEval) eval);
+ }
+ return true;
+ }
+ public ValueEval Result
+ {
+ get
+ {
+ double[] array = new double[values.Count];
+ int pos = 0;
+ foreach(NumericValueEval d in values)
+ {
+ array[pos++] = d.NumberValue;
+ }
+ double var = StatsLib.var(array);
+ return new NumberEval((double) BigDecimal.Parse(NumberToTextConverter.ToText(var)));
+ }
+ }
+
+ public bool AllowEmptyMatchField { get; } = false;
+ }
+}
+
+
diff --git a/main/SS/Formula/Functions/DVarp.cs b/main/SS/Formula/Functions/DVarp.cs
new file mode 100644
index 000000000..0d3921ae1
--- /dev/null
+++ b/main/SS/Formula/Functions/DVarp.cs
@@ -0,0 +1,64 @@
+/* ====================================================================
+ 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.
+==================================================================== */
+
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace NPOI.SS.Formula.Functions
+{
+ using ExtendedNumerics;
+ using NPOI.SS.Formula.Eval;
+ using NPOI.SS.Util;
+ ///
+ /// Implementation of the DVarp function:
+ /// Gets the variance value of a column in an area with given conditions.
+ ///
+ public sealed class DVarp : IDStarAlgorithm
+ {
+ private List values = new List();
+ public bool ProcessMatch(ValueEval eval)
+ {
+ if(eval is NumericValueEval)
+ {
+ values.Add((NumericValueEval) eval);
+ }
+ return true;
+ }
+ public ValueEval Result
+ {
+ get
+ {
+ double[] array = new double[values.Count];
+ int pos = 0;
+ foreach(NumericValueEval d in values)
+ {
+ array[pos++] = d.NumberValue;
+ }
+ double var = StatsLib.varp(array);
+ return new NumberEval((double)BigDecimal.Parse(NumberToTextConverter.ToText(var)));
+ }
+ }
+
+ public bool AllowEmptyMatchField { get; } = false;
+ }
+}
+
+
diff --git a/main/SS/Formula/Functions/IDStarAlgorithm.cs b/main/SS/Formula/Functions/IDStarAlgorithm.cs
index 84f865c51..25cc3ff48 100644
--- a/main/SS/Formula/Functions/IDStarAlgorithm.cs
+++ b/main/SS/Formula/Functions/IDStarAlgorithm.cs
@@ -39,6 +39,12 @@ public interface IDStarAlgorithm
* @return a ValueEval
*/
ValueEval Result { get; }
+ /**
+ * Whether the field value (the 2nd param in DCOUNT, DGET, etc.) can evaluate to empty. It
+ * is allowed to evaluate to empty for DCOUNT.
+ * @return whether the field value can evaluate to empty
+ */
+ bool AllowEmptyMatchField { get; }
}
}
\ No newline at end of file
diff --git a/testcases/main/SS/Formula/Functions/TestDAverage.cs b/testcases/main/SS/Formula/Functions/TestDAverage.cs
new file mode 100644
index 000000000..f2087a3fb
--- /dev/null
+++ b/testcases/main/SS/Formula/Functions/TestDAverage.cs
@@ -0,0 +1,76 @@
+
+/* ====================================================================
+ 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.
+==================================================================== */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace TestCases.SS.Formula.Functions
+{
+ using NPOI.HSSF.UserModel;
+ using NUnit.Framework;
+ using TestCases.SS.Util;
+
+ ///
+ /// Testcase for function DAVERAGE()
+ ///
+ [TestFixture]
+ public class TestDAverage
+ {
+
+ //https://support.microsoft.com/en-us/office/daverage-function-a6a2d5ac-4b4b-48cd-a1d8-7b37834e5aee
+ [Test]
+ public void TestMicrosoftExample1()
+ {
+
+ using(HSSFWorkbook wb = initWorkbook1())
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(12) as HSSFCell;
+ Utils.AssertDouble(fe, cell, "DAVERAGE(A4:E10, \"Yield\", A1:B2)", 12);
+ Utils.AssertDouble(fe, cell, "DAVERAGE(A4:E10, 3, A4:E10)", 13);
+ Utils.AssertDouble(fe, cell, "DAVERAGE(A4:E10, \"Profit\", A12:A13)", 92.6);
+ Utils.AssertDouble(fe, cell, "DAVERAGE(A4:E10, \"Profit\", B12:C13)", 82.5);
+ }
+ }
+
+ private HSSFWorkbook initWorkbook1()
+ {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.CreateSheet() as HSSFSheet;
+ Utils.AddRow(sheet, 0, "Tree", "Height", "Age", "Yield", "Profit", "Height");
+ Utils.AddRow(sheet, 1, "=Apple", ">10", null, null, null, "<16");
+ Utils.AddRow(sheet, 2, "=Pear");
+ Utils.AddRow(sheet, 3, "Tree", "Height", "Age", "Yield", "Profit");
+ Utils.AddRow(sheet, 4, "Apple", 18, 20, 14, 105);
+ Utils.AddRow(sheet, 5, "Pear", 12, 12, 10, 96);
+ Utils.AddRow(sheet, 6, "Cherry", 13, 14, 9, 105);
+ Utils.AddRow(sheet, 7, "Apple", 14, 15, 10, 75);
+ Utils.AddRow(sheet, 8, "Pear", 9, 8, 8, 76.8);
+ Utils.AddRow(sheet, 9, "Apple", 8, 9, 6, 45);
+ Utils.AddRow(sheet, 10);
+ Utils.AddRow(sheet, 11, "Tree", "Height", "Height");
+ Utils.AddRow(sheet, 12, "<>Apple", "<>12", "<>9");
+ return wb;
+ }
+ }
+}
+
+
diff --git a/testcases/main/SS/Formula/Functions/TestDGet.cs b/testcases/main/SS/Formula/Functions/TestDGet.cs
new file mode 100644
index 000000000..1a7f9e78c
--- /dev/null
+++ b/testcases/main/SS/Formula/Functions/TestDGet.cs
@@ -0,0 +1,170 @@
+
+/* ====================================================================
+ 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.
+==================================================================== */
+
+namespace TestCases.SS.Formula.Functions
+{
+ using NPOI.HSSF.UserModel;
+ using NPOI.SS.UserModel;
+ using NUnit.Framework;
+ using TestCases.SS.Util;
+
+
+ ///
+ /// Testcase for function DGET()
+ ///
+ [TestFixture]
+ public class TestDGet
+ {
+
+ //https://support.microsoft.com/en-us/office/dget-function-455568bf-4eef-45f7-90f0-ec250d00892e
+ [Test]
+ public void TestMicrosoftExample1()
+ {
+
+ using(HSSFWorkbook wb = initWorkbook1(false, "=Apple"))
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(100) as HSSFCell;
+ Utils.AssertError(fe, cell, "DGET(A5:E11, \"Yield\", A1:A3)", FormulaError.NUM);
+ Utils.AssertDouble(fe, cell, "DGET(A5:E11, \"Yield\", A1:F3)", 10);
+ Utils.AssertDouble(fe, cell, "DGET(A5:E11, 4, A1:F3)", 10);
+ }
+ }
+
+ [Test]
+ public void TestMicrosoftExample1CaseInsensitive()
+ {
+
+ using(HSSFWorkbook wb = initWorkbook1(false, "=apple"))
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(100) as HSSFCell;
+ Utils.AssertError(fe, cell, "DGET(A5:E11, \"Yield\", A1:A3)", FormulaError.NUM);
+ Utils.AssertDouble(fe, cell, "DGET(A5:E11, \"Yield\", A1:F3)", 10);
+ Utils.AssertDouble(fe, cell, "DGET(A5:E11, 4, A1:F3)", 10);
+ }
+ }
+
+ [Test]
+ public void TestMicrosoftExample1StartsWith()
+ {
+
+ using(HSSFWorkbook wb = initWorkbook1(false, "App"))
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(100) as HSSFCell;
+ Utils.AssertError(fe, cell, "DGET(A5:E11, \"Yield\", A1:A3)", FormulaError.NUM);
+ Utils.AssertDouble(fe, cell, "DGET(A5:E11, \"Yield\", A1:F3)", 10);
+ Utils.AssertDouble(fe, cell, "DGET(A5:E11, 4, A1:F3)", 10);
+ }
+ }
+
+ [Test]
+ public void TestMicrosoftExample1StartsWithLowercase()
+ {
+
+ using(HSSFWorkbook wb = initWorkbook1(false, "app"))
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(100) as HSSFCell;
+ Utils.AssertError(fe, cell, "DGET(A5:E11, \"Yield\", A1:A3)", FormulaError.NUM);
+ Utils.AssertDouble(fe, cell, "DGET(A5:E11, \"Yield\", A1:F3)", 10);
+ Utils.AssertDouble(fe, cell, "DGET(A5:E11, 4, A1:F3)", 10);
+ }
+ }
+
+ [Test]
+ public void TestMicrosoftExample1Wildcard()
+ {
+
+ using(HSSFWorkbook wb = initWorkbook1(false, "A*le"))
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(100) as HSSFCell;
+ Utils.AssertError(fe, cell, "DGET(A5:E11, \"Yield\", A1:A3)", FormulaError.NUM);
+ Utils.AssertDouble(fe, cell, "DGET(A5:E11, \"Yield\", A1:F3)", 10);
+ Utils.AssertDouble(fe, cell, "DGET(A5:E11, 4, A1:F3)", 10);
+ }
+ }
+
+ [Test]
+ public void TestMicrosoftExample1WildcardLowercase()
+ {
+ using(HSSFWorkbook wb = initWorkbook1(false, "a*le"))
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(100) as HSSFCell;
+ Utils.AssertError(fe, cell, "DGET(A5:E11, \"Yield\", A1:A3)", FormulaError.NUM);
+ Utils.AssertDouble(fe, cell, "DGET(A5:E11, \"Yield\", A1:F3)", 10);
+ Utils.AssertDouble(fe, cell, "DGET(A5:E11, 4, A1:F3)", 10);
+ }
+ }
+
+ [Test]
+ public void TestMicrosoftExample1AppleWildcardNoMatch()
+ {
+
+ using(HSSFWorkbook wb = initWorkbook1(false, "A*x"))
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(100) as HSSFCell;
+ Utils.AssertError(fe, cell, "DGET(A5:E11, \"Yield\", A1:A3)", FormulaError.NUM);
+ Utils.AssertError(fe, cell, "DGET(A5:E11, \"Yield\", A1:F3)", FormulaError.VALUE);
+ }
+ }
+
+ [Test]
+ public void TestMicrosoftExample1Variant()
+ {
+
+ using(HSSFWorkbook wb = initWorkbook1(true, "=Apple"))
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(100) as HSSFCell;
+ Utils.AssertDouble(fe, cell, "DGET(A5:E11, \"Yield\", A1:F3)", 6);
+ Utils.AssertDouble(fe, cell, "DGET(A5:E11, 4, A1:F3)", 6);
+ }
+ }
+
+ private HSSFWorkbook initWorkbook1(bool adjustAppleCondition, string appleCondition)
+ {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.CreateSheet() as HSSFSheet;
+ Utils.AddRow(sheet, 0, "Tree", "Height", "Age", "Yield", "Profit", "Height");
+ if(adjustAppleCondition)
+ {
+ Utils.AddRow(sheet, 1, appleCondition, ">=8", null, null, null, "<12");
+ }
+ else
+ {
+ Utils.AddRow(sheet, 1, appleCondition, ">10", null, null, null, "<16");
+ }
+ Utils.AddRow(sheet, 2, "Pear", ">12");
+ Utils.AddRow(sheet, 3);
+ Utils.AddRow(sheet, 4, "Tree", "Height", "Age", "Yield", "Profit");
+ Utils.AddRow(sheet, 5, "Apple", 18, 20, 14, 105);
+ Utils.AddRow(sheet, 6, "Pear", 12, 12, 10, 96);
+ Utils.AddRow(sheet, 7, "Cherry", 13, 14, 9, 105);
+ Utils.AddRow(sheet, 8, "Apple", 14, null, 10, 75);
+ Utils.AddRow(sheet, 9, "Pear", 9, 8, 8, 77);
+ Utils.AddRow(sheet, 10, "Apple", 8, 9, 6, 45);
+ return wb;
+ }
+ }
+}
+
diff --git a/testcases/main/SS/Formula/Functions/TestDProduct.cs b/testcases/main/SS/Formula/Functions/TestDProduct.cs
new file mode 100644
index 000000000..692141124
--- /dev/null
+++ b/testcases/main/SS/Formula/Functions/TestDProduct.cs
@@ -0,0 +1,91 @@
+
+/* ====================================================================
+ 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.
+==================================================================== */
+
+namespace TestCases.SS.Formula.Functions
+{
+ using NPOI.HSSF.UserModel;
+ using NUnit.Framework;
+ using TestCases.SS.Util;
+
+ ///
+ /// Testcase for function DPRODUCT()
+ ///
+ [TestFixture]
+ public class TestDProduct
+ {
+
+ //https://support.microsoft.com/en-us/office/dproduct-function-4f96b13e-d49c-47a7-b769-22f6d017cb31
+ [Test]
+ public void TestMicrosoftExample1()
+ {
+
+ using(HSSFWorkbook wb = initWorkbook1(false))
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(12) as HSSFCell;
+ Utils.AssertDouble(fe, cell, "DPRODUCT(A5:E11, \"Yield\", A1:F3)", 800, 0.0000000001);
+ Utils.AssertDouble(fe, cell, "DPRODUCT(A5:E11, \"Yield\", A13:A14)", 720, 0.0000000001);
+ Utils.AssertDouble(fe, cell, "DPRODUCT(A5:E11, \"Yield\", B13:C14)", 7560, 0.0000000001);
+ }
+ }
+
+ [Test]
+ public void TestNoMatch()
+ {
+
+ using(HSSFWorkbook wb = initWorkbook1(true))
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(12) as HSSFCell;
+ Utils.AssertDouble(fe, cell, "DPRODUCT(A5:E11, \"Yield\", A1:A2)", 0);
+ Utils.AssertDouble(fe, cell, "DPRODUCT(A5:E11, \"Yield\", A1:A3)", 604800);
+ }
+ }
+
+ private HSSFWorkbook initWorkbook1(bool noMatch)
+ {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.CreateSheet() as HSSFSheet;
+ Utils.AddRow(sheet, 0, "Tree", "Height", "Age", "Yield", "Profit", "Height");
+ if(noMatch)
+ {
+ Utils.AddRow(sheet, 1, "=NoMatch");
+ Utils.AddRow(sheet, 2);
+ }
+ else
+ {
+ Utils.AddRow(sheet, 1, "=Apple", ">10", null, null, null, "<16");
+ Utils.AddRow(sheet, 2, "=Pear");
+ }
+ Utils.AddRow(sheet, 3);
+ Utils.AddRow(sheet, 4, "Tree", "Height", "Age", "Yield", "Profit");
+ Utils.AddRow(sheet, 5, "Apple", 18, 20, 14, 105);
+ Utils.AddRow(sheet, 6, "Pear", 12, 12, 10, 96);
+ Utils.AddRow(sheet, 7, "Cherry", 13, 14, 9, 105);
+ Utils.AddRow(sheet, 8, "Apple", 14, 15, 10, 75);
+ Utils.AddRow(sheet, 9, "Pear", 9, 8, 8, 77);
+ Utils.AddRow(sheet, 10, "Apple", 8, 9, 6, 45);
+ Utils.AddRow(sheet, 11);
+ Utils.AddRow(sheet, 12, "Tree", "Height", "Height");
+ Utils.AddRow(sheet, 13, "<>Apple", "<>12", "<>9");
+ return wb;
+ }
+ }
+}
+
+
diff --git a/testcases/main/SS/Formula/Functions/TestDStdev.cs b/testcases/main/SS/Formula/Functions/TestDStdev.cs
new file mode 100644
index 000000000..e44036066
--- /dev/null
+++ b/testcases/main/SS/Formula/Functions/TestDStdev.cs
@@ -0,0 +1,84 @@
+
+/* ====================================================================
+ 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.
+==================================================================== */
+
+namespace TestCases.SS.Formula.Functions
+{
+ using NPOI.HSSF.UserModel;
+ using NUnit.Framework;
+ using TestCases.SS.Util;
+
+ ///
+ /// Testcase for function DSTDEV() and DSTDEVP()
+ ///
+ [TestFixture]
+ public class TestDStdev
+ {
+
+ //https://support.microsoft.com/en-us/office/dstdev-function-026b8c73-616d-4b5e-b072-241871c4ab96
+ [Test]
+ public void TestMicrosoftExample1()
+ {
+
+ using(HSSFWorkbook wb = initWorkbook1())
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(12) as HSSFCell;
+ Utils.AssertDouble(fe, cell, "DSTDEV(A5:E11, \"Yield\", A1:A3)", 2.96647939483827, 0.0000000001);
+ Utils.AssertDouble(fe, cell, "DSTDEV(A5:E11, \"Yield\", B12:C14)", 2.66458251889485, 0.0000000001);
+ }
+ }
+
+ //https://support.microsoft.com/en-us/office/dstdevp-function-04b78995-da03-4813-bbd9-d74fd0f5d94b
+ [Test]
+ public void TestDSTDEVPMicrosoftExample1()
+ {
+
+ using(HSSFWorkbook wb = initWorkbook1())
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(12) as HSSFCell;
+ Utils.AssertDouble(fe, cell, "DSTDEVP(A5:E11, \"Yield\", A1:A3)", 2.65329983228432, 0.0000000001);
+ Utils.AssertDouble(fe, cell, "DSTDEVP(A5:E11, \"Yield\", A12:A13)", 0.816496580927726, 0.0000000001);
+ Utils.AssertDouble(fe, cell, "DSTDEVP(A5:E11, \"Yield\", B12:C14)", 2.43241991988774, 0.0000000001);
+ }
+ }
+
+ private HSSFWorkbook initWorkbook1()
+ {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.CreateSheet() as HSSFSheet;
+ Utils.AddRow(sheet, 0, "Tree", "Height", "Age", "Yield", "Profit", "Height");
+ Utils.AddRow(sheet, 1, "=Apple", ">10", null, null, null, "<16");
+ Utils.AddRow(sheet, 2, "=Pear");
+ Utils.AddRow(sheet, 3);
+ Utils.AddRow(sheet, 4, "Tree", "Height", "Age", "Yield", "Profit");
+ Utils.AddRow(sheet, 5, "Apple", 18, 20, 14, 105);
+ Utils.AddRow(sheet, 6, "Pear", 12, 12, 10, 96);
+ Utils.AddRow(sheet, 7, "Cherry", 13, 14, 9, 105);
+ Utils.AddRow(sheet, 8, "Apple", 14, 15, 10, 75);
+ Utils.AddRow(sheet, 9, "Pear", 9, 8, 8, 77);
+ Utils.AddRow(sheet, 10, "Apple", 8, 9, 6, 45);
+ Utils.AddRow(sheet, 11);
+ Utils.AddRow(sheet, 11, "Tree", "Height", "Height");
+ Utils.AddRow(sheet, 12, "<>Apple", "<>12", "<>9");
+ return wb;
+ }
+ }
+}
+
+
diff --git a/testcases/main/SS/Formula/Functions/TestDVar.cs b/testcases/main/SS/Formula/Functions/TestDVar.cs
new file mode 100644
index 000000000..2aff5f2f2
--- /dev/null
+++ b/testcases/main/SS/Formula/Functions/TestDVar.cs
@@ -0,0 +1,88 @@
+
+/* ====================================================================
+ 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.
+==================================================================== */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace TestCases.SS.Formula.Functions
+{
+ using NPOI.HSSF.UserModel;
+ using NUnit.Framework;
+ using TestCases.SS.Util;
+
+
+ ///
+ /// Testcase for function DVAR() and DVARP()
+ ///
+ [TestFixture]
+ public class TestDVar
+ {
+ //https://support.microsoft.com/en-us/office/dvar-function-d6747ca9-99c7-48bb-996e-9d7af00f3ed1
+ [Test]
+ public void TestMicrosoftExample1()
+ {
+
+ using(HSSFWorkbook wb = initWorkbook1())
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(12) as HSSFCell;
+ Utils.AssertDouble(fe, cell, "DVAR(A4:E10, \"Yield\", A1:A3)", 8.8, 0.0000000001);
+ Utils.AssertDouble(fe, cell, "DVAR(A4:E10, \"Yield\", A12:A13)", 1.0, 0.0000000001);
+ Utils.AssertDouble(fe, cell, "DVAR(A4:E10, \"Yield\", B12:C13)", 10.9166666667, 0.0000000001);
+ }
+ }
+
+ //https://support.microsoft.com/en-us/office/dvarp-function-eb0ba387-9cb7-45c8-81e9-0394912502fc
+ [Test]
+ public void TestDVARPMicrosoftExample1()
+ {
+
+ using(HSSFWorkbook wb = initWorkbook1())
+ {
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ HSSFCell cell = wb.GetSheetAt(0).GetRow(0).CreateCell(12) as HSSFCell;
+ Utils.AssertDouble(fe, cell, "DVARP(A4:E10, \"Yield\", A1:A3)", 7.04, 0.0000000001);
+ Utils.AssertDouble(fe, cell, "DVARP(A4:E10, \"Yield\", A12:A13)", 0.666666666666667, 0.0000000001);
+ Utils.AssertDouble(fe, cell, "DVARP(A4:E10, \"Yield\", B12:C13)", 8.1875, 0.0000000001);
+ }
+ }
+
+ private HSSFWorkbook initWorkbook1()
+ {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.CreateSheet() as HSSFSheet;
+ Utils.AddRow(sheet, 0, "Tree", "Height", "Age", "Yield", "Profit", "Height");
+ Utils.AddRow(sheet, 1, "=Apple", ">10", null, null, null, "<16");
+ Utils.AddRow(sheet, 2, "=Pear");
+ Utils.AddRow(sheet, 3, "Tree", "Height", "Age", "Yield", "Profit");
+ Utils.AddRow(sheet, 4, "Apple", 18, 20, 14, 105);
+ Utils.AddRow(sheet, 5, "Pear", 12, 12, 10, 96);
+ Utils.AddRow(sheet, 6, "Cherry", 13, 14, 9, 105);
+ Utils.AddRow(sheet, 7, "Apple", 14, 15, 10, 75);
+ Utils.AddRow(sheet, 8, "Pear", 9, 8, 8, 77);
+ Utils.AddRow(sheet, 9, "Apple", 8, 9, 6, 45);
+ Utils.AddRow(sheet, 10);
+ Utils.AddRow(sheet, 11, "Tree", "Height", "Height");
+ Utils.AddRow(sheet, 12, "<>Apple", "<>12", "<>9");
+ return wb;
+ }
+ }
+}
diff --git a/testcases/main/SS/Formula/Functions/TestFrequency.cs b/testcases/main/SS/Formula/Functions/TestFrequency.cs
index b78131d96..8f303c0ca 100644
--- a/testcases/main/SS/Formula/Functions/TestFrequency.cs
+++ b/testcases/main/SS/Formula/Functions/TestFrequency.cs
@@ -21,13 +21,12 @@ limitations under the License.
using System.IO;
using System.Text;
-namespace NPOI.SS.Formula.Functions
+namespace TestCases.SS.Formula.Functions
{
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.Util;
- using NPOI.Util.ArrayExtensions;
using NUnit.Framework;
using static NPOI.SS.Formula.Functions.Frequency;
diff --git a/testcases/main/SS/Util/TestPropertyTemplate.cs b/testcases/main/SS/Util/TestPropertyTemplate.cs
index 50e3e39e7..dca636347 100644
--- a/testcases/main/SS/Util/TestPropertyTemplate.cs
+++ b/testcases/main/SS/Util/TestPropertyTemplate.cs
@@ -22,12 +22,11 @@ limitations under the License.
using System.IO;
using System.Text;
-namespace NPOI.SS.Util
+namespace TestCases.SS.Util
{
-
-
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
+ using NPOI.SS.Util;
using NUnit.Framework;
///
diff --git a/testcases/test-data/spreadsheet/DStar.xls b/testcases/test-data/spreadsheet/DStar.xls
index 0c8926142..f53e6f6da 100644
Binary files a/testcases/test-data/spreadsheet/DStar.xls and b/testcases/test-data/spreadsheet/DStar.xls differ