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 ")) + { + 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