git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1044370 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_8_BETA1
<section><title>29 October 2010 - POI 3.7 available</title> | <section><title>29 October 2010 - POI 3.7 available</title> | ||||
<p>The Apache POI team is pleased to announce the release of 3.7. This includes a large number of bug fixes, and some | <p>The Apache POI team is pleased to announce the release of 3.7. This includes a large number of bug fixes, and some | ||||
enhancements (especially text extraction). See the | enhancements (especially text extraction). See the | ||||
<link href="http://www.apache.org/dist/poi/release/bin/RELEASE-NOTES.txt">full release notes</link> for more details. | |||||
<link href="http://www.apache.org/dist/poi/release/bin/RELEASE_NOTES.txt">full release notes</link> for more details. | |||||
</p> | </p> | ||||
<p>A full list of changes is available in the <link href="changes.html">change log</link>. | <p>A full list of changes is available in the <link href="changes.html">change log</link>. | ||||
People interested should also follow the <link href="mailinglists.html">dev mailing list</link> to track further progress.</p> | People interested should also follow the <link href="mailinglists.html">dev mailing list</link> to track further progress.</p> |
<changes> | <changes> | ||||
<release version="3.8-beta1" date="2010-??-??"> | <release version="3.8-beta1" date="2010-??-??"> | ||||
<action dev="POI-DEVELOPERS" type="add">50437 - Support passing ranges to NPV()</action> | |||||
<action dev="POI-DEVELOPERS" type="add">50409 - Added implementation for IRR()</action> | |||||
<action dev="poi-developers" type="add">47405 - Improved performance of RowRecordsAggregate.getStartRowNumberForBlock / getEndRowNumberForBlock</action> | <action dev="poi-developers" type="add">47405 - Improved performance of RowRecordsAggregate.getStartRowNumberForBlock / getEndRowNumberForBlock</action> | ||||
<action dev="poi-developers" type="add">50315 - Avoid crashing Excel when sorting XSSFSheet autofilter</action> | |||||
<action dev="poi-developers" type="fix">50315 - Avoid crashing Excel when sorting XSSFSheet autofilter</action> | |||||
<action dev="poi-developers" type="add">50076 - Allow access from XSSFReader to sheet comments and headers/footers</action> | <action dev="poi-developers" type="add">50076 - Allow access from XSSFReader to sheet comments and headers/footers</action> | ||||
<action dev="poi-developers" type="add">50076 - Refactor XSSFEventBasedExcelExtractor to make it easier for you to have control over outputting the cell contents</action> | <action dev="poi-developers" type="add">50076 - Refactor XSSFEventBasedExcelExtractor to make it easier for you to have control over outputting the cell contents</action> | ||||
<action dev="poi-developers" type="fix">50258 - avoid corruption of XSSFWorkbook after applying XSSFRichTextRun#applyFont</action> | <action dev="poi-developers" type="fix">50258 - avoid corruption of XSSFWorkbook after applying XSSFRichTextRun#applyFont</action> |
retval[58] = FinanceFunction.NPER; | retval[58] = FinanceFunction.NPER; | ||||
retval[59] = FinanceFunction.PMT; | retval[59] = FinanceFunction.PMT; | ||||
retval[62] = new Irr(); | |||||
retval[63] = NumericFunction.RAND; | retval[63] = NumericFunction.RAND; | ||||
retval[64] = new Match(); | retval[64] = new Match(); | ||||
retval[65] = DateFunc.instance; | retval[65] = DateFunc.instance; |
return new NumberEval(result); | return new NumberEval(result); | ||||
} | } | ||||
} | } | ||||
private static final class ValueCollector extends MultiOperandNumericFunction { | |||||
static final class ValueCollector extends MultiOperandNumericFunction { | |||||
private static final ValueCollector instance = new ValueCollector(); | private static final ValueCollector instance = new ValueCollector(); | ||||
public ValueCollector() { | public ValueCollector() { | ||||
super(false, false); | super(false, false); |
* ny + p + f=0 ...{when r=0} | * ny + p + f=0 ...{when r=0} | ||||
* </pre> | * </pre> | ||||
*/ | */ | ||||
final class FinanceLib { | |||||
public final class FinanceLib { | |||||
private FinanceLib() { | private FinanceLib() { | ||||
// no instances of this class | // no instances of this class |
/* ==================================================================== | |||||
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.ss.formula.eval.*; | |||||
/** | |||||
* Calculates the internal rate of return. | |||||
* | |||||
* Syntax is IRR(values) or IRR(values,guess) | |||||
* | |||||
* @author Marcel May | |||||
* @author Yegor Kozlov | |||||
* | |||||
* @see <a href="http://en.wikipedia.org/wiki/Internal_rate_of_return#Numerical_solution">Wikipedia on IRR</a> | |||||
* @see <a href="http://office.microsoft.com/en-us/excel-help/irr-HP005209146.aspx">Excel IRR</a> | |||||
*/ | |||||
public final class Irr implements Function { | |||||
public ValueEval evaluate(final ValueEval[] args, final int srcRowIndex, final int srcColumnIndex) { | |||||
if(args.length == 0 || args.length > 2) { | |||||
// Wrong number of arguments | |||||
return ErrorEval.VALUE_INVALID; | |||||
} | |||||
try { | |||||
double[] values = AggregateFunction.ValueCollector.collectValues(args[0]); | |||||
double guess; | |||||
if(args.length == 2) { | |||||
guess = NumericFunction.singleOperandEvaluate(args[1], srcRowIndex, srcColumnIndex); | |||||
} else { | |||||
guess = 0.1d; | |||||
} | |||||
double result = irr(values, guess); | |||||
NumericFunction.checkValue(result); | |||||
return new NumberEval(result); | |||||
} catch (EvaluationException e){ | |||||
return e.getErrorEval(); | |||||
} | |||||
} | |||||
/** | |||||
* Computes the internal rate of return using an estimated irr of 10 percent. | |||||
* | |||||
* @param income the income values. | |||||
* @return the irr. | |||||
*/ | |||||
public static double irr(double[] income) { | |||||
return irr(income, 0.1d); | |||||
} | |||||
/** | |||||
* Calculates IRR using the Newton-Raphson Method. | |||||
* <p> | |||||
* Starting with the guess, the method cycles through the calculation until the result | |||||
* is accurate within 0.00001 percent. If IRR can't find a result that works | |||||
* after 20 tries, the Double.NaN<> is returned. | |||||
* </p> | |||||
* <p> | |||||
* The implementation is inspired by the NewtonSolver from the Apache Commons-Math library, | |||||
* @see {http://commons.apache.org/} | |||||
* </p> | |||||
* | |||||
* @param values the income values. | |||||
* @param guess the initial guess of irr. | |||||
* @return the irr value. The method returns <code>Double.NaN</code> | |||||
* if the maximum iteration count is exceeded | |||||
* | |||||
* @see {http://en.wikipedia.org/wiki/Internal_rate_of_return#Numerical_solution} | |||||
* @see {http://en.wikipedia.org/wiki/Newton%27s_method} | |||||
*/ | |||||
public static double irr(double[] values, double guess) { | |||||
int maxIterationCount = 20; | |||||
double absoluteAccuracy = 1E-7; | |||||
double x0 = guess; | |||||
double x1; | |||||
int i = 0; | |||||
while (i < maxIterationCount) { | |||||
// the value of the function (NPV) and its derivate can be calculated in the same loop | |||||
double fValue = 0; | |||||
double fDerivative = 0; | |||||
for (int k = 0; k < values.length; k++) { | |||||
fValue += values[k] / Math.pow(1.0 + x0, k); | |||||
fDerivative += -k * values[k] / Math.pow(1.0 + x0, k + 1); | |||||
} | |||||
// the essense of the Newton-Raphson Method | |||||
x1 = x0 - fValue/fDerivative; | |||||
if (Math.abs(x1 - x0) <= absoluteAccuracy) { | |||||
return x1; | |||||
} | |||||
x0 = x1; | |||||
++i; | |||||
} | |||||
// maximum number of iterations is exceeded | |||||
return Double.NaN; | |||||
} | |||||
} |
package org.apache.poi.ss.formula.functions; | package org.apache.poi.ss.formula.functions; | ||||
import org.apache.poi.ss.formula.TwoDEval; | |||||
import org.apache.poi.ss.formula.eval.ErrorEval; | import org.apache.poi.ss.formula.eval.ErrorEval; | ||||
import org.apache.poi.ss.formula.eval.EvaluationException; | import org.apache.poi.ss.formula.eval.EvaluationException; | ||||
import org.apache.poi.ss.formula.eval.NumberEval; | import org.apache.poi.ss.formula.eval.NumberEval; | ||||
import org.apache.poi.ss.formula.eval.ValueEval; | import org.apache.poi.ss.formula.eval.ValueEval; | ||||
import java.util.Arrays; | |||||
/** | /** | ||||
* Calculates the net present value of an investment by using a discount rate | * Calculates the net present value of an investment by using a discount rate | ||||
* and a series of future payments (negative values) and income (positive | * and a series of future payments (negative values) and income (positive | ||||
* income. | * income. | ||||
* | * | ||||
* @author SPetrakovsky | * @author SPetrakovsky | ||||
* @author Marcel May | |||||
*/ | */ | ||||
public final class Npv implements Function2Arg, Function3Arg, Function4Arg { | |||||
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) { | |||||
double result; | |||||
try { | |||||
double rate = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex); | |||||
double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex); | |||||
result = evaluate(rate, d1); | |||||
NumericFunction.checkValue(result); | |||||
} catch (EvaluationException e) { | |||||
return e.getErrorEval(); | |||||
} | |||||
return new NumberEval(result); | |||||
} | |||||
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, | |||||
ValueEval arg2) { | |||||
double result; | |||||
try { | |||||
double rate = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex); | |||||
double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex); | |||||
double d2 = NumericFunction.singleOperandEvaluate(arg2, srcRowIndex, srcColumnIndex); | |||||
result = evaluate(rate, d1, d2); | |||||
NumericFunction.checkValue(result); | |||||
} catch (EvaluationException e) { | |||||
return e.getErrorEval(); | |||||
} | |||||
return new NumberEval(result); | |||||
} | |||||
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, | |||||
ValueEval arg2, ValueEval arg3) { | |||||
double result; | |||||
try { | |||||
double rate = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex); | |||||
double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex); | |||||
double d2 = NumericFunction.singleOperandEvaluate(arg2, srcRowIndex, srcColumnIndex); | |||||
double d3 = NumericFunction.singleOperandEvaluate(arg3, srcRowIndex, srcColumnIndex); | |||||
result = evaluate(rate, d1, d2, d3); | |||||
NumericFunction.checkValue(result); | |||||
} catch (EvaluationException e) { | |||||
return e.getErrorEval(); | |||||
} | |||||
return new NumberEval(result); | |||||
} | |||||
public final class Npv implements Function { | |||||
public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) { | public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) { | ||||
int nArgs = args.length; | int nArgs = args.length; | ||||
if (nArgs<2) { | |||||
if (nArgs < 2) { | |||||
return ErrorEval.VALUE_INVALID; | return ErrorEval.VALUE_INVALID; | ||||
} | } | ||||
int np = nArgs-1; | |||||
double[] ds = new double[np]; | |||||
double result; | |||||
try { | |||||
try { | |||||
double rate = NumericFunction.singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex); | double rate = NumericFunction.singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex); | ||||
for (int i = 0; i < ds.length; i++) { | |||||
ds[i] = NumericFunction.singleOperandEvaluate(args[i+1], srcRowIndex, srcColumnIndex); | |||||
} | |||||
result = evaluate(rate, ds); | |||||
// convert tail arguments into an array of doubles | |||||
ValueEval[] vargs = Arrays.copyOfRange(args, 1 , args.length); | |||||
double[] values = AggregateFunction.ValueCollector.collectValues(vargs); | |||||
double result = FinanceLib.npv(rate, values); | |||||
NumericFunction.checkValue(result); | NumericFunction.checkValue(result); | ||||
return new NumberEval(result); | |||||
} catch (EvaluationException e) { | } catch (EvaluationException e) { | ||||
return e.getErrorEval(); | return e.getErrorEval(); | ||||
} | } | ||||
return new NumberEval(result); | |||||
} | |||||
private static double evaluate(double rate, double...ds) { | |||||
double sum = 0; | |||||
for (int i = 0; i < ds.length; i++) { | |||||
sum += ds[i] / Math.pow(rate + 1, i); | |||||
} | |||||
return sum; | |||||
} | } | ||||
} | } |
/* ==================================================================== | |||||
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 junit.framework.TestCase; | |||||
import junit.framework.AssertionFailedError; | |||||
import org.apache.poi.hssf.usermodel.*; | |||||
import org.apache.poi.hssf.HSSFTestDataSamples; | |||||
import org.apache.poi.ss.usermodel.CellValue; | |||||
/** | |||||
* Tests for {@link Irr} | |||||
* | |||||
* @author Marcel May | |||||
*/ | |||||
public final class TestIrr extends TestCase { | |||||
public void testIrr() { | |||||
// http://en.wikipedia.org/wiki/Internal_rate_of_return#Example | |||||
double[] incomes = {-4000d, 1200d, 1410d, 1875d, 1050d}; | |||||
double irr = Irr.irr(incomes); | |||||
double irrRounded = Math.round(irr * 1000d) / 1000d; | |||||
assertEquals("irr", 0.143d, irrRounded); | |||||
// http://www.techonthenet.com/excel/formulas/irr.php | |||||
incomes = new double[]{-7500d, 3000d, 5000d, 1200d, 4000d}; | |||||
irr = Irr.irr(incomes); | |||||
irrRounded = Math.round(irr * 100d) / 100d; | |||||
assertEquals("irr", 0.28d, irrRounded); | |||||
incomes = new double[]{-10000d, 3400d, 6500d, 1000d}; | |||||
irr = Irr.irr(incomes); | |||||
irrRounded = Math.round(irr * 100d) / 100d; | |||||
assertEquals("irr", 0.05, irrRounded); | |||||
incomes = new double[]{100d, -10d, -110d}; | |||||
irr = Irr.irr(incomes); | |||||
irrRounded = Math.round(irr * 100d) / 100d; | |||||
assertEquals("irr", 0.1, irrRounded); | |||||
incomes = new double[]{-70000d, 12000, 15000}; | |||||
irr = Irr.irr(incomes, -0.1); | |||||
irrRounded = Math.round(irr * 100d) / 100d; | |||||
assertEquals("irr", -0.44, irrRounded); | |||||
} | |||||
public void testEvaluateInSheet() { | |||||
HSSFWorkbook wb = new HSSFWorkbook(); | |||||
HSSFSheet sheet = wb.createSheet("Sheet1"); | |||||
HSSFRow row = sheet.createRow(0); | |||||
row.createCell(0).setCellValue(-4000d); | |||||
row.createCell(1).setCellValue(1200d); | |||||
row.createCell(2).setCellValue(1410d); | |||||
row.createCell(3).setCellValue(1875d); | |||||
row.createCell(4).setCellValue(1050d); | |||||
HSSFCell cell = row.createCell(5); | |||||
cell.setCellFormula("IRR(A1:E1)"); | |||||
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); | |||||
fe.clearAllCachedResultValues(); | |||||
fe.evaluateFormulaCell(cell); | |||||
double res = cell.getNumericCellValue(); | |||||
assertEquals(0.143d, Math.round(res * 1000d) / 1000d); | |||||
} | |||||
public void testIrrFromSpreadsheet(){ | |||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("IrrNpvTestCaseData.xls"); | |||||
HSSFSheet sheet = wb.getSheet("IRR-NPV"); | |||||
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); | |||||
StringBuffer failures = new StringBuffer(); | |||||
int failureCount = 0; | |||||
// TODO YK: Formulas in rows 16 and 17 operate with ArrayPtg which isn't yet supported | |||||
// FormulaEvaluator as of r1041407 throws "Unexpected ptg class (org.apache.poi.ss.formula.ptg.ArrayPtg)" | |||||
for(int rownum = 9; rownum <= 15; rownum++){ | |||||
HSSFRow row = sheet.getRow(rownum); | |||||
HSSFCell cellA = row.getCell(0); | |||||
try { | |||||
CellValue cv = fe.evaluate(cellA); | |||||
assertFormulaResult(cv, cellA); | |||||
} catch (Throwable e){ | |||||
if(failures.length() > 0) failures.append('\n'); | |||||
failures.append("Row[" + (cellA.getRowIndex() + 1)+ "]: " + cellA.getCellFormula() + " "); | |||||
failures.append(e.getMessage()); | |||||
failureCount++; | |||||
} | |||||
HSSFCell cellC = row.getCell(2); //IRR-NPV relationship: NPV(IRR(values), values) = 0 | |||||
try { | |||||
CellValue cv = fe.evaluate(cellC); | |||||
assertEquals(0, cv.getNumberValue(), 0.0001); // should agree within 0.01% | |||||
} catch (Throwable e){ | |||||
if(failures.length() > 0) failures.append('\n'); | |||||
failures.append("Row[" + (cellC.getRowIndex() + 1)+ "]: " + cellC.getCellFormula() + " "); | |||||
failures.append(e.getMessage()); | |||||
failureCount++; | |||||
} | |||||
} | |||||
if(failures.length() > 0) { | |||||
throw new AssertionFailedError(failureCount + " IRR assertions failed:\n" + failures.toString()); | |||||
} | |||||
} | |||||
private static void assertFormulaResult(CellValue cv, HSSFCell cell){ | |||||
double actualValue = cv.getNumberValue(); | |||||
double expectedValue = cell.getNumericCellValue(); // cached formula result calculated by Excel | |||||
assertEquals("Invalid formula result: " + cv.toString(), HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType()); | |||||
assertEquals(expectedValue, actualValue, 1E-4); // should agree within 0.01% | |||||
} | |||||
} |
/* ==================================================================== | |||||
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 junit.framework.TestCase; | |||||
import junit.framework.AssertionFailedError; | |||||
import org.apache.poi.hssf.usermodel.*; | |||||
import org.apache.poi.hssf.HSSFTestDataSamples; | |||||
import org.apache.poi.ss.usermodel.Cell; | |||||
import org.apache.poi.ss.usermodel.Row; | |||||
import org.apache.poi.ss.usermodel.CellValue; | |||||
/** | |||||
* Tests for {@link Npv} | |||||
* | |||||
* @author Marcel May | |||||
* @see <a href="http://office.microsoft.com/en-us/excel-help/npv-HP005209199.aspx">Excel Help</a> | |||||
*/ | |||||
public final class TestNpv extends TestCase { | |||||
public void testEvaluateInSheetExample2() { | |||||
HSSFWorkbook wb = new HSSFWorkbook(); | |||||
HSSFSheet sheet = wb.createSheet("Sheet1"); | |||||
HSSFRow row = sheet.createRow(0); | |||||
sheet.createRow(1).createCell(0).setCellValue(0.08d); | |||||
sheet.createRow(2).createCell(0).setCellValue(-40000d); | |||||
sheet.createRow(3).createCell(0).setCellValue(8000d); | |||||
sheet.createRow(4).createCell(0).setCellValue(9200d); | |||||
sheet.createRow(5).createCell(0).setCellValue(10000d); | |||||
sheet.createRow(6).createCell(0).setCellValue(12000d); | |||||
sheet.createRow(7).createCell(0).setCellValue(14500d); | |||||
HSSFCell cell = row.createCell(8); | |||||
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); | |||||
// Enumeration | |||||
cell.setCellFormula("NPV(A2, A4,A5,A6,A7,A8)+A3"); | |||||
fe.clearAllCachedResultValues(); | |||||
fe.evaluateFormulaCell(cell); | |||||
double res = cell.getNumericCellValue(); | |||||
assertEquals(1922.06d, Math.round(res * 100d) / 100d); | |||||
// Range | |||||
cell.setCellFormula("NPV(A2, A4:A8)+A3"); | |||||
fe.clearAllCachedResultValues(); | |||||
fe.evaluateFormulaCell(cell); | |||||
res = cell.getNumericCellValue(); | |||||
assertEquals(1922.06d, Math.round(res * 100d) / 100d); | |||||
} | |||||
/** | |||||
* evaluate formulas with NPV and compare the result with | |||||
* the cached formula result pre-calculated by Excel | |||||
*/ | |||||
public void testNpvFromSpreadsheet(){ | |||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("IrrNpvTestCaseData.xls"); | |||||
HSSFSheet sheet = wb.getSheet("IRR-NPV"); | |||||
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); | |||||
StringBuffer failures = new StringBuffer(); | |||||
int failureCount = 0; | |||||
// TODO YK: Formulas in rows 16 and 17 operate with ArrayPtg which isn't yet supported | |||||
// FormulaEvaluator as of r1041407 throws "Unexpected ptg class (org.apache.poi.ss.formula.ptg.ArrayPtg)" | |||||
for(int rownum = 9; rownum <= 15; rownum++){ | |||||
HSSFRow row = sheet.getRow(rownum); | |||||
HSSFCell cellB = row.getCell(1); | |||||
try { | |||||
CellValue cv = fe.evaluate(cellB); | |||||
assertFormulaResult(cv, cellB); | |||||
} catch (Throwable e){ | |||||
if(failures.length() > 0) failures.append('\n'); | |||||
failures.append("Row[" + (cellB.getRowIndex() + 1)+ "]: " + cellB.getCellFormula() + " "); | |||||
failures.append(e.getMessage()); | |||||
failureCount++; | |||||
} | |||||
} | |||||
if(failures.length() > 0) { | |||||
throw new AssertionFailedError(failureCount + " IRR evaluations failed:\n" + failures.toString()); | |||||
} | |||||
} | |||||
private static void assertFormulaResult(CellValue cv, HSSFCell cell){ | |||||
double actualValue = cv.getNumberValue(); | |||||
double expectedValue = cell.getNumericCellValue(); // cached formula result calculated by Excel | |||||
assertEquals(expectedValue, actualValue, 1E-4); // should agree within 0.01% | |||||
} | |||||
} |