[github-733] Fix rate order in Mirr function. Thanks to Aleksandrs Jansons. This closes #733

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1922095 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
PJ Fanning 2024-11-25 20:48:45 +00:00
parent 0d63f9a814
commit edb9aeaca5
3 changed files with 29 additions and 35 deletions

View File

@ -56,23 +56,20 @@ public class Mirr extends MultiOperandNumericFunction {
@Override @Override
protected double evaluate(double[] values) throws EvaluationException { protected double evaluate(double[] values) throws EvaluationException {
double financeRate = values[values.length-1]; double financeRate = values[values.length-2];
double reinvestRate = values[values.length-2]; double reinvestRate = values[values.length-1];
double[] mirrValues = Arrays.copyOf(values, values.length - 2); double[] mirrValues = Arrays.copyOf(values, values.length - 2);
boolean mirrValuesAreAllNegatives = true; boolean mirrValuesAreAllNegatives = true;
boolean mirrValuesAreAllPositives = true;
for (double mirrValue : mirrValues) { for (double mirrValue : mirrValues) {
mirrValuesAreAllNegatives &= mirrValue < 0; mirrValuesAreAllNegatives &= mirrValue < 0;
mirrValuesAreAllPositives &= mirrValue > 0;
} }
if (mirrValuesAreAllNegatives) { if (mirrValuesAreAllNegatives) {
return -1.0d; return -1.0d;
} }
boolean mirrValuesAreAllPositives = true;
for (double mirrValue : mirrValues) {
mirrValuesAreAllPositives &= mirrValue > 0;
}
if (mirrValuesAreAllPositives) { if (mirrValuesAreAllPositives) {
throw new EvaluationException(ErrorEval.DIV_ZERO); throw new EvaluationException(ErrorEval.DIV_ZERO);
} }
@ -87,15 +84,11 @@ public class Mirr extends MultiOperandNumericFunction {
double fv = 0; double fv = 0;
int indexN = 0; int indexN = 0;
for (double anIn : in) {
if (anIn < 0) {
pv += anIn / Math.pow(1 + financeRate + reinvestRate, indexN++);
}
}
for (double anIn : in) { for (double anIn : in) {
if (anIn > 0) { if (anIn > 0) {
fv += anIn * Math.pow(1 + financeRate, numOfYears - indexN++); fv += anIn * Math.pow(1 + reinvestRate, numOfYears - indexN++);
} else if (anIn < 0) {
pv += anIn / Math.pow(1 + financeRate, indexN++);
} }
} }

View File

@ -44,43 +44,44 @@ final class TestMirr {
Mirr mirr = new Mirr(); Mirr mirr = new Mirr();
double mirrValue; double mirrValue;
double financeRate = 0.12; double financeRate = 0.1;
double reinvestRate = 0.1; double reinvestRate = 0.12;
double[] values = {-120000d, 39000d, 30000d, 21000d, 37000d, 46000d, reinvestRate, financeRate}; double[] values = {-120000d, 39000d, 30000d, 21000d, 37000d, 46000d, financeRate, reinvestRate};
// MIRR should not failed with these parameters
mirrValue = mirr.evaluate(values); mirrValue = mirr.evaluate(values);
assertEquals(0.126094130366, mirrValue, 0.0000000001); assertEquals(0.126094130366, mirrValue, 0.0000000001);
reinvestRate = 0.05; financeRate = 0.05;
financeRate = 0.08; reinvestRate = 0.08;
values = new double[]{-7500d, 3000d, 5000d, 1200d, 4000d, reinvestRate, financeRate}; values = new double[]{-7500d, 3000d, 5000d, 1200d, 4000d, financeRate, reinvestRate};
// MIRR should not failed with these parameters
mirrValue = mirr.evaluate(values); mirrValue = mirr.evaluate(values);
assertEquals(0.18736225093, mirrValue, 0.0000000001); assertEquals(0.18736225093, mirrValue, 0.0000000001);
reinvestRate = 0.065; financeRate = 0.065;
financeRate = 0.1; reinvestRate = 0.1;
values = new double[]{-10000, 3400d, 6500d, 1000d, reinvestRate, financeRate}; values = new double[]{-10000, 3400d, 6500d, 1000d, financeRate, reinvestRate};
// MIRR should not failed with these parameters
mirrValue = mirr.evaluate(values); mirrValue = mirr.evaluate(values);
assertEquals(0.07039493966, mirrValue, 0.0000000001); assertEquals(0.07039493966, mirrValue, 0.0000000001);
reinvestRate = 0.07; financeRate = 0.07;
financeRate = 0.01; reinvestRate = 0.01;
values = new double[]{-10000d, -3400d, -6500d, -1000d, reinvestRate, financeRate}; values = new double[]{-10000d, -3400d, -6500d, -1000d, financeRate, reinvestRate};
// MIRR should not failed with these parameters
mirrValue = mirr.evaluate(values); mirrValue = mirr.evaluate(values);
assertEquals(-1, mirrValue, 0.0); assertEquals(-1, mirrValue, 0.0);
financeRate = 0.1;
reinvestRate = 0.12;
values = new double[]{-1000d, -4000d, 5000d, 2000d, financeRate, reinvestRate};
mirrValue = mirr.evaluate(values);
assertEquals(0.179085686035, mirrValue, 0.0000000001);
} }
@Test @Test
void testMirrErrors_expectDIV0() { void testMirrErrors_expectDIV0() {
Mirr mirr = new Mirr(); Mirr mirr = new Mirr();
double reinvestRate = 0.05;
double financeRate = 0.08; double financeRate = 0.08;
double[] incomes = {120000d, 39000d, 30000d, 21000d, 37000d, 46000d, reinvestRate, financeRate}; double reinvestRate = 0.05;
double[] incomes = {120000d, 39000d, 30000d, 21000d, 37000d, 46000d, financeRate, reinvestRate};
EvaluationException e = assertThrows(EvaluationException.class, () -> mirr.evaluate(incomes)); EvaluationException e = assertThrows(EvaluationException.class, () -> mirr.evaluate(incomes));
assertEquals(ErrorEval.DIV_ZERO, e.getErrorEval()); assertEquals(ErrorEval.DIV_ZERO, e.getErrorEval());
@ -117,7 +118,7 @@ final class TestMirr {
HSSFSheet sheet = wb.getSheet("Mirr"); HSSFSheet sheet = wb.getSheet("Mirr");
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
int failureCount = 0; int failureCount = 0;
int[] resultRows = {9, 19, 29, 45}; int[] resultRows = {9, 19, 29, 45, 53};
for (int rowNum : resultRows) { for (int rowNum : resultRows) {
HSSFRow row = sheet.getRow(rowNum); HSSFRow row = sheet.getRow(rowNum);

Binary file not shown.