Author: yegor
Date: Fri Dec 10 14:20:35 2010
New Revision: 1044370

URL: http://svn.apache.org/viewvc?rev=1044370&view=rev
Log:
Support for IRR() function, see Bugzilla 50409. Includes fix for Bugzilla 50437

Added:
    poi/trunk/src/java/org/apache/poi/ss/formula/functions/Irr.java
    poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestIrr.java
    poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestNpv.java
    poi/trunk/test-data/spreadsheet/IrrNpvTestCaseData.xls   (with props)
Modified:
    poi/trunk/src/documentation/content/xdocs/index.xml
    poi/trunk/src/documentation/content/xdocs/status.xml
    poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java
    
poi/trunk/src/java/org/apache/poi/ss/formula/functions/AggregateFunction.java
    poi/trunk/src/java/org/apache/poi/ss/formula/functions/FinanceLib.java
    poi/trunk/src/java/org/apache/poi/ss/formula/functions/Npv.java

Modified: poi/trunk/src/documentation/content/xdocs/index.xml
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/index.xml?rev=1044370&r1=1044369&r2=1044370&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/index.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/index.xml Fri Dec 10 14:20:35 2010
@@ -35,7 +35,7 @@
     <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
         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>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>

Modified: poi/trunk/src/documentation/content/xdocs/status.xml
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/status.xml?rev=1044370&r1=1044369&r2=1044370&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/status.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/status.xml Fri Dec 10 14:20:35 
2010
@@ -34,8 +34,10 @@
 
     <changes>
         <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">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 - 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>

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java?rev=1044370&r1=1044369&r2=1044370&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java Fri Dec 
10 14:20:35 2010
@@ -100,6 +100,7 @@ public final class FunctionEval {
                retval[58] = FinanceFunction.NPER;
                retval[59] = FinanceFunction.PMT;
 
+               retval[62] = new Irr();
                retval[63] = NumericFunction.RAND;
                retval[64] = new Match();
                retval[65] = DateFunc.instance;

Modified: 
poi/trunk/src/java/org/apache/poi/ss/formula/functions/AggregateFunction.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/functions/AggregateFunction.java?rev=1044370&r1=1044369&r2=1044370&view=diff
==============================================================================
--- 
poi/trunk/src/java/org/apache/poi/ss/formula/functions/AggregateFunction.java 
(original)
+++ 
poi/trunk/src/java/org/apache/poi/ss/formula/functions/AggregateFunction.java 
Fri Dec 10 14:20:35 2010
@@ -67,7 +67,7 @@ public abstract class AggregateFunction 
                        return new NumberEval(result);
                }
        }
-       private static final class ValueCollector extends 
MultiOperandNumericFunction {
+       static final class ValueCollector extends MultiOperandNumericFunction {
                private static final ValueCollector instance = new 
ValueCollector();
                public ValueCollector() {
                        super(false, false);

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/functions/FinanceLib.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/functions/FinanceLib.java?rev=1044370&r1=1044369&r2=1044370&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/functions/FinanceLib.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/functions/FinanceLib.java Fri 
Dec 10 14:20:35 2010
@@ -56,7 +56,7 @@ package org.apache.poi.ss.formula.functi
  * ny + p + f=0                            ...{when r=0}
  * </pre>
  */
-final class FinanceLib {
+public final class FinanceLib {
 
     private FinanceLib() {
         // no instances of this class

Added: poi/trunk/src/java/org/apache/poi/ss/formula/functions/Irr.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/functions/Irr.java?rev=1044370&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/functions/Irr.java (added)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/functions/Irr.java Fri Dec 10 
14:20:35 2010
@@ -0,0 +1,120 @@
+/* ====================================================================
+   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;
+    }
+}

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/functions/Npv.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/functions/Npv.java?rev=1044370&r1=1044369&r2=1044370&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/functions/Npv.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/functions/Npv.java Fri Dec 10 
14:20:35 2010
@@ -17,11 +17,14 @@
 
 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.EvaluationException;
 import org.apache.poi.ss.formula.eval.NumberEval;
 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
  * and a series of future payments (negative values) and income (positive
@@ -30,78 +33,27 @@ import org.apache.poi.ss.formula.eval.Va
  * income.
  *
  * @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) {
                int nArgs = args.length;
-               if (nArgs<2) {
+               if (nArgs < 2) {
                        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);
-                       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);
+            return new NumberEval(result);
                } catch (EvaluationException e) {
                        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;
        }
 }

Added: poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestIrr.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestIrr.java?rev=1044370&view=auto
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestIrr.java 
(added)
+++ poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestIrr.java 
Fri Dec 10 14:20:35 2010
@@ -0,0 +1,128 @@
+/* ====================================================================
+   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%
+    }
+}

Added: poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestNpv.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestNpv.java?rev=1044370&view=auto
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestNpv.java 
(added)
+++ poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestNpv.java 
Fri Dec 10 14:20:35 2010
@@ -0,0 +1,104 @@
+/* ====================================================================
+   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%
+    }
+}

Added: poi/trunk/test-data/spreadsheet/IrrNpvTestCaseData.xls
URL: 
http://svn.apache.org/viewvc/poi/trunk/test-data/spreadsheet/IrrNpvTestCaseData.xls?rev=1044370&view=auto
==============================================================================
Binary file - no diff available.

Propchange: poi/trunk/test-data/spreadsheet/IrrNpvTestCaseData.xls
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to