From: PJ Fanning Date: Sun, 10 Oct 2021 13:23:01 +0000 (+0000) Subject: [bug-64137] increase max iterations for IRR X-Git-Tag: REL_5_2_0~406 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=08f6de47f69c22de37299d62e00c780350d3dc1a;p=poi.git [bug-64137] increase max iterations for IRR git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1894110 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/poi/src/main/java/org/apache/poi/ss/formula/functions/Irr.java b/poi/src/main/java/org/apache/poi/ss/formula/functions/Irr.java index e9480c68c3..f8ee32e799 100644 --- a/poi/src/main/java/org/apache/poi/ss/formula/functions/Irr.java +++ b/poi/src/main/java/org/apache/poi/ss/formula/functions/Irr.java @@ -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 Excel IRR */ 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 { *

* 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. * *

* 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; } } diff --git a/poi/src/test/java/org/apache/poi/ss/formula/functions/TestIrr.java b/poi/src/test/java/org/apache/poi/ss/formula/functions/TestIrr.java index 289fc826c9..d6351a9aaf 100644 --- a/poi/src/test/java/org/apache/poi/ss/formula/functions/TestIrr.java +++ b/poi/src/test/java/org/apache/poi/ss/formula/functions/TestIrr.java @@ -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