Skip to content

Commit 2333fc9

Browse files
swmalswmal
andauthored
#2223 - GROWTH and TREND did not handle single value newX parameter (#2225)
* #2223 - GROWTH did not handle single value newX parameter * #2223 - TREND did not handle single value newX parameter --------- Co-authored-by: swmal <{ID}+username}@users.noreply.github.com>
1 parent d8f82db commit 2333fc9

4 files changed

Lines changed: 187 additions & 15 deletions

File tree

src/EPPlus/FormulaParsing/Excel/Functions/Statistical/Growth.cs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Date Author Change
1515
using OfficeOpenXml.FormulaParsing.Excel.Functions.Metadata;
1616
using OfficeOpenXml.FormulaParsing.ExcelUtilities;
1717
using OfficeOpenXml.FormulaParsing.FormulaExpressions;
18+
using OfficeOpenXml.FormulaParsing.Ranges;
1819
using System;
1920
using System.Collections.Generic;
2021
using System.Linq;
@@ -79,10 +80,24 @@ public override CompileResult Execute(IList<FunctionArgument> arguments, Parsing
7980
}
8081

8182
//If newXs is given:
82-
if (arguments[2].IsExcelRange)
83+
if(arguments.Count() > 2 && arguments[2].DataType != DataType.Empty)
8384
{
84-
argNewX = arguments[2].ValueAsRangeInfo;
85-
if (multipleXranges)
85+
if (arguments[2].IsExcelRange)
86+
{
87+
argNewX = arguments[2].ValueAsRangeInfo;
88+
}
89+
else if (arguments[2] != null && arguments[2].DataType != DataType.Empty && IsNumeric(arguments[2].Value))
90+
{
91+
var n = ArgToDecimal(arguments, 2, out ExcelErrorValue e3);
92+
if (e3 != null) return CreateResult(e3.Type);
93+
var xValsList = new List<double> { n };
94+
return CreateDynamicArrayResult(GrowthHelper.GetGrowthValuesSingle(xValsList.ToArray(), coefficients, columnArray), DataType.ExcelRange);
95+
}
96+
else
97+
{
98+
argNewX = null;
99+
}
100+
if (multipleXranges && argNewX != null)
86101
{
87102
//knownXs and NewXs must have the same amount of variables, but doesnt have to have the same amount of observations/samples
88103
if (columnArray && argNewX.Size.NumberOfCols != argX.Size.NumberOfCols) return CompileResult.GetErrorResult(eErrorType.Ref);
@@ -91,14 +106,16 @@ public override CompileResult Execute(IList<FunctionArgument> arguments, Parsing
91106
var xRanges = LinestHelper.GetRangeAsJaggedDouble(argNewX, argY, constVar, multipleXranges);
92107
return CreateDynamicArrayResult(GrowthHelper.GetGrowthValuesMultiple(xRanges, coefficients, constVar, columnArray), DataType.ExcelRange);
93108
}
94-
else
109+
else if(argNewX != null)
95110
{
96-
RangeFlattener.GetNumericPairLists(argNewX, argY, !multipleXranges, out List<double> xVals, out List<double> yVals);
97-
var xValsArray = MatrixHelper.ListToArray(xVals);
111+
//RangeFlattener.GetNumericPairLists(argNewX, argY, !multipleXranges, out List<double> xVals, out List<double> yVals);
112+
List<double?> xValsArray = RangeFlattener.FlattenRange(argNewX, false);
113+
//var xValsArray = MatrixHelper.ListToArray(xVals);
98114
if (argNewX.Size.NumberOfCols == 1) columnArray = true;
99-
return CreateDynamicArrayResult(GrowthHelper.GetGrowthValuesSingle(xValsArray, coefficients, columnArray), DataType.ExcelRange);
115+
return CreateDynamicArrayResult(GrowthHelper.GetGrowthValuesSingle(xValsArray.Where(x => x.HasValue).Select(x => (double)x).ToArray(), coefficients, columnArray), DataType.ExcelRange);
100116
}
101117
}
118+
102119

103120
//If newXs is omitted:
104121
if (multipleXranges)

src/EPPlus/FormulaParsing/Excel/Functions/Statistical/Trend.cs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,24 @@ public override CompileResult Execute(IList<FunctionArgument> arguments, Parsing
7979
}
8080

8181
//If newXs is given:
82-
if (arguments[2].IsExcelRange)
82+
if (arguments.Count() > 2 && arguments[2].DataType != DataType.Empty)
8383
{
84-
argNewX = arguments[2].ValueAsRangeInfo;
85-
if (multipleXranges)
84+
if (arguments[2].IsExcelRange)
85+
{
86+
argNewX = arguments[2].ValueAsRangeInfo;
87+
}
88+
else if (arguments[2] != null && arguments[2].DataType != DataType.Empty && IsNumeric(arguments[2].Value))
89+
{
90+
var n = ArgToDecimal(arguments, 2, out ExcelErrorValue e3);
91+
if (e3 != null) return CreateResult(e3.Type);
92+
var xValsList = new List<double> { n };
93+
return CreateDynamicArrayResult(TrendHelper.GetTrendValuesSingle(xValsList.ToArray(), coefficients, columnArray), DataType.ExcelRange);
94+
}
95+
else
96+
{
97+
argNewX = null;
98+
}
99+
if (multipleXranges && argNewX != null)
86100
{
87101
//knownXs and NewXs must have the same amount of variables, but doesnt have to have the same amount of observations/samples
88102
if (columnArray && argNewX.Size.NumberOfCols != argX.Size.NumberOfCols) return CompileResult.GetErrorResult(eErrorType.Ref);
@@ -91,15 +105,14 @@ public override CompileResult Execute(IList<FunctionArgument> arguments, Parsing
91105
var xRanges = LinestHelper.GetRangeAsJaggedDouble(argNewX, argY, constVar, multipleXranges);
92106
return CreateDynamicArrayResult(TrendHelper.GetTrendValuesMultiple(xRanges, coefficients, constVar, columnArray), DataType.ExcelRange);
93107
}
94-
else
108+
else if (argNewX != null)
95109
{
96-
RangeFlattener.GetNumericPairLists(argNewX, argY, !multipleXranges, out List<double> xVals, out List<double> yVals);
97-
var xValsArray = MatrixHelper.ListToArray(xVals);
110+
List<double?> xValsArray = RangeFlattener.FlattenRange(argNewX, false);
98111
if (argNewX.Size.NumberOfCols == 1) columnArray = true;
99-
return CreateDynamicArrayResult(TrendHelper.GetTrendValuesSingle(xValsArray, coefficients, columnArray), DataType.ExcelRange);
112+
return CreateDynamicArrayResult(TrendHelper.GetTrendValuesSingle(xValsArray.Where(x => x.HasValue).Select(x => (double)x).ToArray(), coefficients, columnArray), DataType.ExcelRange);
100113
}
101114
}
102-
115+
103116
//If newXs is omitted:
104117
if (multipleXranges)
105118
{

src/EPPlusTest/FormulaParsing/Excel/Functions/Statistical/GrowthTest.cs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.VisualStudio.TestTools.UnitTesting;
22
using OfficeOpenXml;
3+
using System;
34
using System.IO;
45

56
namespace EPPlusTest.FormulaParsing.Excel.Functions.Statistical
@@ -429,5 +430,87 @@ public void GrowthNegativeNumberTest()
429430
Assert.AreEqual(ExcelErrorValue.Create(eErrorType.Num), result1);
430431
}
431432
}
433+
434+
[TestMethod]
435+
public void GrowthShouldHandleSingleNumberNewx()
436+
{
437+
using var pkg = new ExcelPackage();
438+
var ws = pkg.Workbook.Worksheets.Add("Sheet1");
439+
440+
// Data: y = 2^x
441+
ws.Cells["A1"].Value = 2; ws.Cells["B1"].Value = 1;
442+
ws.Cells["A2"].Value = 4; ws.Cells["B2"].Value = 2;
443+
ws.Cells["A3"].Value = 8; ws.Cells["B3"].Value = 3;
444+
445+
ws.Cells["C1"].Value = 4;
446+
ws.Cells["C2"].Value = 3;
447+
ws.Cells["C3"].Value = 4;
448+
449+
// Block where GROWTH incorrectly tries to spill
450+
ws.Cells["D2"].Value = "blocker";
451+
452+
// GROWTH(known_y, known_x, new_x=4) should return 16 (single value for x=4)
453+
// EPPlus ignores new_x, returns array [2,4,8] for known_x, tries to spill -> #VALUE!
454+
ws.Cells["D1"].Formula = "GROWTH(A1:A3,B1:B3,4)";
455+
456+
pkg.Workbook.Calculate();
457+
458+
var d1 = System.Math.Round((double)ws.Cells["D1"].Value);
459+
460+
Assert.AreEqual(16D, d1);
461+
}
462+
463+
[TestMethod]
464+
public void GrowthShouldHandlTwoArgs()
465+
{
466+
using var pkg = new ExcelPackage();
467+
var ws = pkg.Workbook.Worksheets.Add("Sheet1");
468+
469+
ws.Cells["A1"].Value = 2; ws.Cells["B1"].Value = 1;
470+
ws.Cells["A2"].Value = 4; ws.Cells["B2"].Value = 2;
471+
ws.Cells["A3"].Value = 8; ws.Cells["B3"].Value = 3;
472+
473+
ws.Cells["C1"].Value = 4;
474+
ws.Cells["C2"].Value = 3;
475+
ws.Cells["C3"].Value = 4;
476+
477+
ws.Cells["D1"].Formula = "GROWTH(A1:A3,B1:B3)";
478+
479+
pkg.Workbook.Calculate();
480+
481+
var d1 = System.Math.Round((double)ws.Cells["D1"].Value);
482+
var d2 = System.Math.Round((double)ws.Cells["D2"].Value);
483+
var d3 = System.Math.Round((double)ws.Cells["D3"].Value);
484+
485+
Assert.AreEqual(2d, d1);
486+
Assert.AreEqual(4d, d2);
487+
Assert.AreEqual(8d, d3);
488+
}
489+
490+
[TestMethod]
491+
public void GrowthShouldHandleThreeRanges()
492+
{
493+
using var pkg = new ExcelPackage();
494+
var ws = pkg.Workbook.Worksheets.Add("Sheet1");
495+
496+
ws.Cells["A1"].Value = 2; ws.Cells["B1"].Value = 1;
497+
ws.Cells["A2"].Value = 4; ws.Cells["B2"].Value = 2;
498+
ws.Cells["A3"].Value = 8; ws.Cells["B3"].Value = 3;
499+
500+
ws.Cells["C1"].Value = 4;
501+
ws.Cells["C2"].Value = 3;
502+
ws.Cells["C3"].Value = 4;
503+
504+
ws.Cells["D1"].Formula = "GROWTH(A1:A3,B1:B3,C1:C2)";
505+
506+
pkg.Workbook.Calculate();
507+
508+
var d1 = System.Math.Round((double)ws.Cells["D1"].Value);
509+
var d2 = System.Math.Round((double)ws.Cells["D2"].Value);
510+
511+
Assert.AreEqual(16d, d1);
512+
Assert.AreEqual(8d, d2);
513+
Assert.IsNull(ws.Cells["D3"].Value);
514+
}
432515
}
433516
}

src/EPPlusTest/FormulaParsing/Excel/Functions/Statistical/TrendTest.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,65 @@ public void TrendTestDefaultXCols()
365365
}
366366
}
367367

368+
[TestMethod]
369+
public void TrendShouldHandleSingleNumberNewx()
370+
{
371+
using var pkg = new ExcelPackage();
372+
var ws = pkg.Workbook.Worksheets.Add("Sheet1");
373+
374+
// Data: y = 2^x
375+
ws.Cells["A1"].Value = 2; ws.Cells["B1"].Value = 1;
376+
ws.Cells["A2"].Value = 4; ws.Cells["B2"].Value = 2;
377+
ws.Cells["A3"].Value = 8; ws.Cells["B3"].Value = 3;
378+
379+
ws.Cells["C1"].Value = 4;
380+
ws.Cells["C2"].Value = 3;
381+
ws.Cells["C3"].Value = 4;
382+
383+
// Block where GROWTH incorrectly tries to spill
384+
ws.Cells["D2"].Value = "blocker";
385+
386+
// GROWTH(known_y, known_x, new_x=4) should return 16 (single value for x=4)
387+
// EPPlus ignores new_x, returns array [2,4,8] for known_x, tries to spill -> #VALUE!
388+
ws.Cells["D1"].Formula = "TREND(A1:A3,B1:B3,4)";
389+
390+
pkg.Workbook.Calculate();
391+
392+
Assert.IsInstanceOfType(ws.Cells["D1"].Value, typeof(double));
393+
394+
var d1 = System.Math.Round((double)ws.Cells["D1"].Value, 5);
395+
396+
Assert.AreEqual(10.66667, d1);
397+
}
398+
399+
[TestMethod]
400+
public void TrendShouldHandleThreeRanges()
401+
{
402+
using var pkg = new ExcelPackage();
403+
var ws = pkg.Workbook.Worksheets.Add("Sheet1");
404+
405+
ws.Cells["A1"].Value = 2; ws.Cells["B1"].Value = 1;
406+
ws.Cells["A2"].Value = 4; ws.Cells["B2"].Value = 2;
407+
ws.Cells["A3"].Value = 8; ws.Cells["B3"].Value = 3;
408+
409+
ws.Cells["C1"].Value = 4;
410+
ws.Cells["C2"].Value = 3;
411+
ws.Cells["C3"].Value = 4;
412+
413+
ws.Cells["D1"].Formula = "TREND(A1:A3,B1:B3,C1:C2)";
414+
415+
pkg.Workbook.Calculate();
416+
417+
var d1 = System.Math.Round((double)ws.Cells["D1"].Value, 5);
418+
var d2 = System.Math.Round((double)ws.Cells["D2"].Value, 5);
419+
420+
Assert.AreEqual(10.66667d, d1);
421+
Assert.AreEqual(7.66667d, d2);
422+
Assert.IsNull(ws.Cells["D3"].Value);
423+
}
424+
425+
426+
368427
//[TestMethod]
369428

370429
//public void WorkBookTest()

0 commit comments

Comments
 (0)