diff --git a/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs b/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs index 12e0995..2d1368d 100644 --- a/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs +++ b/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs @@ -1,3 +1,4 @@ +using ClosedXML.Excel.CalcEngine.Exceptions; using ClosedXML.Excel.CalcEngine.Functions; using System; using System.Collections; @@ -64,7 +65,7 @@ ce.RegisterFunction("SUBTOTAL", 2, 255, Subtotal); ce.RegisterFunction("SUM", 1, int.MaxValue, Sum); ce.RegisterFunction("SUMIF", 2, 3, SumIf); - //ce.RegisterFunction("SUMPRODUCT", 1, SumProduct); + ce.RegisterFunction("SUMPRODUCT", 1, 30, SumProduct); ce.RegisterFunction("SUMSQ", 1, 255, SumSq); //ce.RegisterFunction("SUMX2MY2", SumX2MY2, 1); //ce.RegisterFunction("SUMX2PY2", SumX2PY2, 1); @@ -261,6 +262,37 @@ return tally.Sum(); } + private static object SumProduct(List p) + { + // all parameters should be IEnumerable + if (p.Any(param => !(param is IEnumerable))) + throw new NoValueAvailableException(); + + var counts = p.Cast().Select(param => + { + int i = 0; + foreach (var item in param) + i++; + return i; + }) + .Distinct(); + + // All parameters should have the same length + if (counts.Count() > 1) + throw new NoValueAvailableException(); + + var values = p + .Cast() + .Select(range => range.Cast().ToList()); + + return Enumerable.Range(0, counts.Single()) + .Aggregate(0d, (t, i) => + t + values.Aggregate(1d, + (product, list) => product * list[i] + ) + ); + } + private static object Tan(List p) { return Math.Tan(p[0]); diff --git a/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs b/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs index 5012bb5..b9003d2 100644 --- a/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs +++ b/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs @@ -1,6 +1,8 @@ using ClosedXML.Excel; +using ClosedXML.Excel.CalcEngine.Exceptions; using NUnit.Framework; using System; +using System.Linq; namespace ClosedXML_Tests.Excel.CalcEngine { @@ -119,5 +121,23 @@ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(6.2, 1.1)"); Assert.AreEqual(0.7, actual, tolerance); } + + [Test] + public void SumProduct() + { + using (var wb = new XLWorkbook()) + { + var ws = wb.AddWorksheet("Sheet1"); + + ws.FirstCell().Value = Enumerable.Range(1, 10); + ws.FirstCell().CellRight().Value = Enumerable.Range(1, 10).Reverse(); + + Assert.AreEqual(2, ws.Evaluate("SUMPRODUCT(A2)")); + Assert.AreEqual(55, ws.Evaluate("SUMPRODUCT(A1:A10)")); + Assert.AreEqual(220, ws.Evaluate("SUMPRODUCT(A1:A10, B1:B10)")); + + Assert.Throws(() => ws.Evaluate("SUMPRODUCT(A1:A10, B1:B5)")); + } + } } }