diff --git a/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs b/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs index d4fc266..12ea4e7 100644 --- a/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs +++ b/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs @@ -24,6 +24,7 @@ ce.RegisterFunction("ATANH", 1, Atanh); ce.RegisterFunction("CEILING", 1, Ceiling); ce.RegisterFunction("COMBIN", 2, Combin); + ce.RegisterFunction("COMBINA", 2, CombinA); ce.RegisterFunction("COS", 1, Cos); ce.RegisterFunction("COSH", 1, Cosh); ce.RegisterFunction("COT", 1, Cot); @@ -421,6 +422,24 @@ return XLMath.Combin(n, k); } + private static object CombinA(List p) + { + Int32 number = (int)p[0]; // casting truncates towards 0 as specified + Int32 chosen = (int)p[1]; + + if (number < 0 || number < chosen) + throw new NumberException(); + if (chosen < 0) + throw new NumberException(); + + int n = number + chosen - 1; + int k = number - 1; + + return n == k || k == 0 + ? 1 + : (long)XLMath.Combin(n, k); + } + private static object Degrees(List p) { return p[0] * (180.0 / Math.PI); diff --git a/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs b/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs index dd2eeef..c3cd7ce 100644 --- a/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs +++ b/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs @@ -12,6 +12,46 @@ { private readonly double tolerance = 1e-10; + [TestCase(4, 3, 20)] + [TestCase(10, 3, 220)] + [TestCase(0, 0, 1)] + public void Combina_CalculatesCorrectValues(int number, int chosen, int expectedResult) + { + var actualResult = XLWorkbook.EvaluateExpr($"COMBINA({number}, {chosen})"); + Assert.AreEqual(expectedResult, (long)actualResult); + } + + [Theory] + public void Combina_Returns1WhenChosenIs0([Range(0, 10)]int number) + { + Combina_CalculatesCorrectValues(number, 0, 1); + } + + [TestCase(4.23, 3, 20)] + [TestCase(10.4, 3.14, 220)] + [TestCase(0, 0.4, 1)] + public void Combina_TruncatesNumbersCorrectly(double number, double chosen, int expectedResult) + { + var actualResult = XLWorkbook.EvaluateExpr(string.Format( + @"COMBINA({0}, {1})", + number.ToString(CultureInfo.InvariantCulture), + chosen.ToString(CultureInfo.InvariantCulture))); + + Assert.AreEqual(expectedResult, (long)actualResult); + } + + [TestCase(-1, 2)] + [TestCase(-3, -2)] + [TestCase(2, -2)] + public void Combina_ThrowsNumExceptionOnInvalidValues(int number, int chosen) + { + Assert.Throws(() => XLWorkbook.EvaluateExpr( + string.Format( + @"COMBINA({0}, {1})", + number.ToString(CultureInfo.InvariantCulture), + chosen.ToString(CultureInfo.InvariantCulture)))); + } + [TestCase(1, 0.642092616)] [TestCase(2, -0.457657554)] [TestCase(3, -7.015252551)]