diff --git a/src/Numerics/SpecialFunctions/Factorial.cs b/src/Numerics/SpecialFunctions/Factorial.cs index 6807062a..d3d9a976 100644 --- a/src/Numerics/SpecialFunctions/Factorial.cs +++ b/src/Numerics/SpecialFunctions/Factorial.cs @@ -93,6 +93,38 @@ namespace MathNet.Numerics return GammaLn(x + 1.0); } + /// + /// Computes the binomial coefficient: n choose k. + /// + /// A nonnegative value n. + /// A nonnegative value h. + /// The binomial coefficient: n choose k. + public static double Binomial(int n, int k) + { + if (k < 0 || n < 0 || k > n) + { + return 0.0; + } + + return Math.Floor(0.5 + Math.Exp(FactorialLn(n) - FactorialLn(k) - FactorialLn(n - k))); + } + + /// + /// Computes the natural logarithm of the binomial coefficient: ln(n choose k). + /// + /// A nonnegative value n. + /// A nonnegative value h. + /// The logarithmic binomial coefficient: ln(n choose k). + public static double BinomialLn(int n, int k) + { + if (k < 0 || n < 0 || k > n) + { + return Double.NegativeInfinity; + } + + return FactorialLn(n) - FactorialLn(k) - FactorialLn(n - k); + } + private static double[] GenerateFactorials(int max) { var cache = new double[max + 1]; diff --git a/src/UnitTests/SpecialFunctionsTests/FactorialTest.cs b/src/UnitTests/SpecialFunctionsTests/FactorialTest.cs index 38dc6448..7c1ec6b9 100644 --- a/src/UnitTests/SpecialFunctionsTests/FactorialTest.cs +++ b/src/UnitTests/SpecialFunctionsTests/FactorialTest.cs @@ -78,5 +78,29 @@ namespace MathNet.Numerics.UnitTests.SpecialFunctionsTests AssertHelpers.AlmostEqual(307933.81973375485425, SpecialFunctions.FactorialLn(1 << 15), 14); AssertHelpers.AlmostEqual(1413421.9939462073242, SpecialFunctions.FactorialLn(1 << 17), 14); } + + [Test] + public void CanComputeBinomial() + { + AssertHelpers.AlmostEqual(1, SpecialFunctions.Binomial(1, 1), 14); + AssertHelpers.AlmostEqual(10, SpecialFunctions.Binomial(5, 2), 14); + AssertHelpers.AlmostEqual(35, SpecialFunctions.Binomial(7, 3), 14); + AssertHelpers.AlmostEqual(1, SpecialFunctions.Binomial(1, 0), 14); + AssertHelpers.AlmostEqual(0, SpecialFunctions.Binomial(0, 1), 14); + AssertHelpers.AlmostEqual(0, SpecialFunctions.Binomial(5, 7), 14); + AssertHelpers.AlmostEqual(0, SpecialFunctions.Binomial(5, -7), 14); + } + + [Test] + public void CanComputeBinomialLn() + { + AssertHelpers.AlmostEqual(Math.Log(1), SpecialFunctions.BinomialLn(1, 1), 14); + AssertHelpers.AlmostEqual(Math.Log(10), SpecialFunctions.BinomialLn(5, 2), 14); + AssertHelpers.AlmostEqual(Math.Log(35), SpecialFunctions.BinomialLn(7, 3), 14); + AssertHelpers.AlmostEqual(Math.Log(1), SpecialFunctions.BinomialLn(1, 0), 14); + AssertHelpers.AlmostEqual(Math.Log(0), SpecialFunctions.BinomialLn(0, 1), 14); + AssertHelpers.AlmostEqual(Math.Log(0), SpecialFunctions.BinomialLn(5, 7), 14); + AssertHelpers.AlmostEqual(Math.Log(0), SpecialFunctions.BinomialLn(5, -7), 14); + } } } \ No newline at end of file