From 54e533889aaa94e2d272940ef32505bc5406eedc Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sun, 1 Apr 2018 15:52:13 +0000 Subject: [PATCH] [bug-62121] Fixed Power function of negative numbers. Thanks to Bob van den Berge. This closes #104 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1828143 13f79535-47bb-0310-9956-ffa450edef68 --- .../eval/TwoOperandNumericOperation.java | 3 + .../poi/ss/formula/eval/TestPowerEval.java | 98 +++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 src/testcases/org/apache/poi/ss/formula/eval/TestPowerEval.java diff --git a/src/java/org/apache/poi/ss/formula/eval/TwoOperandNumericOperation.java b/src/java/org/apache/poi/ss/formula/eval/TwoOperandNumericOperation.java index 60c3b31f5..e5e131583 100644 --- a/src/java/org/apache/poi/ss/formula/eval/TwoOperandNumericOperation.java +++ b/src/java/org/apache/poi/ss/formula/eval/TwoOperandNumericOperation.java @@ -106,6 +106,9 @@ public abstract class TwoOperandNumericOperation extends Fixed2ArgFunction imple }; public static final Function PowerEval = new TwoOperandNumericOperation() { protected double evaluate(double d0, double d1) { + if(d0 < 0 && Math.abs(d1) > 0.0 && Math.abs(d1) < 1.0) { + return -1 * Math.pow(d0 * -1, d1); + } return Math.pow(d0, d1); } }; diff --git a/src/testcases/org/apache/poi/ss/formula/eval/TestPowerEval.java b/src/testcases/org/apache/poi/ss/formula/eval/TestPowerEval.java new file mode 100644 index 000000000..eb7e36791 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/TestPowerEval.java @@ -0,0 +1,98 @@ +/* ==================================================================== + 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.eval; + +import junit.framework.TestCase; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.formula.functions.Function; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.CellValue; + +/** + * Tests for power operator evaluator. + * + * @author Bob van den Berge + */ +public final class TestPowerEval extends TestCase { + + public void testPositiveValues() { + confirm(0, 0, 1); + confirm(1, 1, 0); + confirm(9, 3, 2); + } + + public void testNegativeValues() { + confirm(-1, -1, 1); + confirm(1, 1, -1); + confirm(1, -10, 0); + confirm((1.0/3), 3, -1); + } + + public void testPositiveDecimalValues() { + confirm(3, 27, (1/3.0)); + } + + public void testNegativeDecimalValues() { + confirm(-3, -27, (1/3.0)); + } + + public void testErrorValues() { + confirmError(-1.00001, 1.1); + } + + public void testInSpreadSheet() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet("Sheet1"); + HSSFRow row = sheet.createRow(0); + HSSFCell cell = row.createCell(0); + cell.setCellFormula("B1^C1"); + row.createCell(1).setCellValue(-27); + row.createCell(2).setCellValue((1/3.0)); + + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + CellValue cv = fe.evaluate(cell); + + assertEquals(CellType.NUMERIC, cv.getCellType()); + assertEquals(-3.0, cv.getNumberValue()); + } + + private void confirm(double expected, double a, double b) { + NumberEval result = (NumberEval) evaluate(EvalInstances.Power, a, b); + + assertEquals(expected, result.getNumberValue()); + } + + private void confirmError(double a, double b) { + ErrorEval result = (ErrorEval) evaluate(EvalInstances.Power, a, b); + + assertEquals("#NUM!", result.getErrorString()); + } + + private static ValueEval evaluate(Function instance, double... dArgs) { + ValueEval[] evalArgs; + evalArgs = new ValueEval[dArgs.length]; + for (int i = 0; i < evalArgs.length; i++) { + evalArgs[i] = new NumberEval(dArgs[i]); + } + return instance.evaluate(evalArgs, -1, (short) -1); + } +}