add AVERAGEA function

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1901299 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
PJ Fanning 2022-05-26 22:23:48 +00:00
parent e94b376880
commit c84eee1b8e
4 changed files with 128 additions and 9 deletions

View File

@ -333,13 +333,13 @@ public final class FunctionEval {
// 358: GETPIVOTDATA
retval[359] = new Hyperlink();
// 360: PHONETIC
// 361: AVERAGEA
retval[361] = AggregateFunction.AVERAGEA;
retval[362] = MinaMaxa.MAXA;
retval[363] = MinaMaxa.MINA;
// 364: STDEVPA
// 365: VARPA
// 366: STDEVA
// 367: VARA
retval[366] = AggregateFunction.STDEVA;
retval[367] = AggregateFunction.VARA;
for (int i = 0; i < retval.length; i++) {
Function f = retval[i];

View File

@ -187,6 +187,21 @@ public abstract class AggregateFunction extends MultiOperandNumericFunction {
}
};
public static final Function AVERAGE = new AggregateFunction() {
@Override
protected double evaluate(double[] values) throws EvaluationException {
if (values.length < 1) {
throw new EvaluationException(ErrorEval.DIV_ZERO);
}
return MathX.average(values);
}
};
public static final Function AVERAGEA = new AggregateFunction() {
@Override
protected boolean handleLogicalValues() {
return true;
}
@Override
protected double evaluate(double[] values) throws EvaluationException {
if (values.length < 1) {
throw new EvaluationException(ErrorEval.DIV_ZERO);
@ -236,6 +251,20 @@ public abstract class AggregateFunction extends MultiOperandNumericFunction {
return StatsLib.stdevp(values);
}
};
public static final Function STDEVA = new AggregateFunction() {
@Override
protected boolean handleLogicalValues() {
return true;
}
@Override
protected double evaluate(double[] values) throws EvaluationException {
if (values.length < 1) {
throw new EvaluationException(ErrorEval.DIV_ZERO);
}
return StatsLib.stdev(values);
}
};
public static final Function SUM = new AggregateFunction() {
protected double evaluate(double[] values) {
return MathX.sum(values);
@ -262,6 +291,20 @@ public abstract class AggregateFunction extends MultiOperandNumericFunction {
return StatsLib.varp(values);
}
};
public static final Function VARA = new AggregateFunction() {
@Override
protected boolean handleLogicalValues() {
return true;
}
@Override
protected double evaluate(double[] values) throws EvaluationException {
if (values.length < 1) {
throw new EvaluationException(ErrorEval.DIV_ZERO);
}
return StatsLib.var(values);
}
};
public static final Function GEOMEAN = new Geomean();
private static class Product extends AggregateFunction {

View File

@ -96,6 +96,17 @@ public abstract class MultiOperandNumericFunction implements Function {
blankConsumer = ConsumerFactory.createForBlank(policy);
}
/**
* Functions like AVERAGEA() differ from AVERAGE() in the way they handle non-numeric cells.
* AVERAGEA treats booleans as 1.0 (true) and 0.0 (false). For strings, they should be parsed as numbers.
* When the string is not a number, treat it as 0.0.
*
* @return whether to parse non-numeric cells
*/
protected boolean handleLogicalValues() {
return false;
}
public final ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
try {
double[] values = getNumberArray(args);
@ -169,7 +180,7 @@ public abstract class MultiOperandNumericFunction implements Function {
ValueEval ve = ae.getValue(sIx, rrIx, rcIx);
if (!isSubtotalCounted() && ae.isSubTotal(rrIx, rcIx)) continue;
if (!isHiddenRowCounted() && ae.isRowHidden(rrIx)) continue;
collectValue(ve, true, temp);
collectValue(ve, !handleLogicalValues(), temp);
}
}
}
@ -183,7 +194,7 @@ public abstract class MultiOperandNumericFunction implements Function {
for (int rcIx = 0; rcIx < width; rcIx++) {
ValueEval ve = ae.getValue(rrIx, rcIx);
if (!isSubtotalCounted() && ae.isSubTotal(rrIx, rcIx)) continue;
collectValue(ve, true, temp);
collectValue(ve, !handleLogicalValues(), temp);
}
}
return;
@ -191,7 +202,7 @@ public abstract class MultiOperandNumericFunction implements Function {
if (operand instanceof RefEval) {
RefEval re = (RefEval) operand;
for (int sIx = re.getFirstSheetIndex(); sIx <= re.getLastSheetIndex(); sIx++) {
collectValue(re.getInnerValueEval(sIx), true, temp);
collectValue(re.getInnerValueEval(sIx), !handleLogicalValues(), temp);
}
return;
}
@ -221,12 +232,17 @@ public abstract class MultiOperandNumericFunction implements Function {
// ignore all ref strings
return;
}
String s = ((StringValueEval) ve).getStringValue();
String s = ((StringValueEval) ve).getStringValue().trim();
Double d = OperandResolver.parseDouble(s);
if (d == null) {
throw new EvaluationException(ErrorEval.VALUE_INVALID);
if (handleLogicalValues()) {
temp.add(0.0);
} else {
throw new EvaluationException(ErrorEval.VALUE_INVALID);
}
} else {
temp.add(d.doubleValue());
}
temp.add(d.doubleValue());
return;
}
if (ve instanceof ErrorEval) {

View File

@ -0,0 +1,60 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.ss.formula.functions;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import static org.apache.poi.ss.util.Utils.addRow;
import static org.apache.poi.ss.util.Utils.assertDouble;
/**
* Testcase for AVERAGEA() functions
*/
public class TestAverageA {
//https://support.microsoft.com/en-us/office/averagea-function-f5f84098-d453-4f4c-bbba-3d2c66356091
@Test
void testMicrosoftExample1() throws IOException {
try (HSSFWorkbook wb = initWorkbook1()) {
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
HSSFCell cell = wb.getSheetAt(0).getRow(0).createCell(12);
assertDouble(fe, cell, "AVERAGEA(A2:A6)", 5.6, 0.00000000001);
assertDouble(fe, cell, "AVERAGEA(A2:A5,A7)", 5.6, 0.00000000001);
assertDouble(fe, cell, "AVERAGE(A2:A6)", 7, 0.00000000001);
}
}
private HSSFWorkbook initWorkbook1() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
addRow(sheet, 0, "Data");
addRow(sheet, 1, 10);
addRow(sheet, 2, 7);
addRow(sheet, 3, 9);
addRow(sheet, 4, 2);
addRow(sheet, 5, "Not available");
addRow(sheet, 6, "Formula");
return wb;
}
}