]> source.dussan.org Git - poi.git/commitdiff
[bug-64137] increase max iterations for IRR
authorPJ Fanning <fanningpj@apache.org>
Sun, 10 Oct 2021 13:23:01 +0000 (13:23 +0000)
committerPJ Fanning <fanningpj@apache.org>
Sun, 10 Oct 2021 13:23:01 +0000 (13:23 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1894110 13f79535-47bb-0310-9956-ffa450edef68

poi/src/main/java/org/apache/poi/ss/formula/functions/Irr.java
poi/src/test/java/org/apache/poi/ss/formula/functions/TestIrr.java

index e9480c68c37c8bc4b79c4ff38ce5de2ec45f2f3a..f8ee32e799408e68b7381cb740f7c14fd5f9a47d 100644 (file)
@@ -17,6 +17,8 @@
 
 package org.apache.poi.ss.formula.functions;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.poi.ss.formula.eval.ErrorEval;
 import org.apache.poi.ss.formula.eval.EvaluationException;
 import org.apache.poi.ss.formula.eval.NumberEval;
@@ -31,8 +33,9 @@ import org.apache.poi.ss.formula.eval.ValueEval;
  * @see <a href="http://office.microsoft.com/en-us/excel-help/irr-HP005209146.aspx">Excel IRR</a>
  */
 public final class Irr implements Function {
-    private static final int MAX_ITERATION_COUNT = 20;
+    private static final int MAX_ITERATION_COUNT = 1000;
     private static final double ABSOLUTE_ACCURACY = 1E-7;
+    private static final Logger LOGGER = LogManager.getLogger(Irr.class);
 
 
     public ValueEval evaluate(final ValueEval[] args, final int srcRowIndex, final int srcColumnIndex) {
@@ -73,7 +76,7 @@ public final class Irr implements Function {
      * <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 {@code Double.NaN} is returned.
+     * after 1000 tries, the {@code Double.NaN} is returned.
      *
      * <p>
      *   The implementation is inspired by the NewtonSolver from the Apache Commons-Math library,
@@ -96,10 +99,11 @@ public final class Irr implements Function {
 
         for (int i = 0; i < MAX_ITERATION_COUNT; i++) {
 
-            // the value of the function (NPV) and its derivate can be calculated in the same loop
+            // the value of the function (NPV) and its derivation can be calculated in the same loop
             final double factor = 1.0 + x0;
             double denominator = factor;
             if (denominator == 0) {
+                LOGGER.atWarn().log("Returning NaN because IRR has found an denominator of 0");
                 return Double.NaN;
             }
 
@@ -114,6 +118,7 @@ public final class Irr implements Function {
 
             // the essence of the Newton-Raphson Method
             if (fDerivative == 0) {
+                LOGGER.atWarn().log("Returning NaN because IRR has found an fDerivative of 0");
                 return Double.NaN;
             }
             double x1 =  x0 - fValue/fDerivative;
@@ -125,6 +130,7 @@ public final class Irr implements Function {
             x0 = x1;
         }
         // maximum number of iterations is exceeded
+        LOGGER.atWarn().log("Returning NaN because IRR has reached max number of iterations allowed: {}", MAX_ITERATION_COUNT);
         return Double.NaN;
     }
 }
index 289fc826c96ce4442fa0bb7b5133572145d41f77..d6351a9aaf5a5599710ba68f4b3ecc8a0beae582 100644 (file)
@@ -143,6 +143,20 @@ final class TestIrr {
         }
     }
 
+    @Test
+    void bug64137() {
+        double[] incomes = {-30000.0, -49970.7425, 29.2575, 146.2875, 380.34749999999997, 581.5, 581.5,
+                731.4374999999999, 731.4374999999999, 731.4374999999999, 877.725, 877.725, 877.725, 1024.0125,
+                1024.0125, 1024.0125, 1170.3, 1170.3, 1170.3, 1170.3, 1316.5874999999999, 1316.5874999999999,
+                1316.5874999999999, 1316.5874999999999, 1462.8749999999998, 1462.8749999999998, 1462.8749999999998,
+                1462.8749999999998, 1462.8749999999998, 1462.8749999999998, 1462.8749999999998, 1462.8749999999998,
+                1462.8749999999998, 1462.8749999999998, 1462.8749999999998, 1462.8749999999998, 1462.8749999999998,
+                1462.8749999999998, 1462.8749999999998, 1462.8749999999998, 1462.8749999999998, 1462.8749999999998,
+                1462.8749999999998, 1462.8749999999998, 1462.8749999999998, 10000.0};
+        double result = Irr.irr(incomes);
+        assertEquals(-0.009463562705856032, result);
+    }
+
     private static void assertFormulaResult(CellValue cv, HSSFCell cell){
         double actualValue = cv.getNumberValue();
         double expectedValue = cell.getNumericCellValue(); // cached formula result calculated by Excel