/// <summary> /// Creates an instance whose range is the k-element subsets of /// {0, ..., n - 1} represented as <c>int[]</c> arrays. /// <para> /// If the <c>iterationOrder</c> argument is set to /// <see cref="IterationOrder.LEXICOGRAPHIC"/>, the arrays returned by the /// <see cref="iterator()"/> are sorted in descending order and /// they are visited in lexicographic order with significance from /// right to left. /// For example, <c>new Combinations(4, 2).iterator()</c> returns /// an iterator that will generate the following sequence of arrays /// on successive calls to /// <c>next()</c>:<para/> /// <c>[0, 1], [0, 2], [1, 2], [0, 3], [1, 3], [2, 3]</c> /// </para> /// If <c>k == 0</c> an iterator containing an empty array is returned; /// if <c>k == n</c> an iterator containing [0, ..., n - 1] is returned. /// /// </summary> /// <param name="n">Size of the set from which subsets are selected.</param> /// <param name="k">Size of the subsets to be enumerated.></param> /// <param name="iterationOrder">Specifies the <see cref="iterator()"/>.</param> /// <exception cref="NotPositiveException"> if <c>n < 0</c>.</exception> /// <exception cref="NumberIsTooLargeException"> if <c>k > n</c>.</exception> private Combinations(int n, int k, IterationOrder iterationOrder) { CombinatoricsUtils.checkBinomial(n, k); this.n = n; this.k = k; this.iterationOrder = iterationOrder; }
/// <summary> /// Returns a <c>double</c> representation of the <a /// href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial /// Coefficient</a>, "<c>n choose k</c>", the number of /// <c>k</c>-element subsets that can be selected from an /// <c>n</c>-element set. /// <para> /// Preconditions: /// <list type="bullet"> /// <item> <c>0 <= k <= n</c> (otherwise /// <c>IllegalArgumentException</c> is thrown)</item> /// <item> The result is small enough to fit into a <c>double</c>. The /// largest value of <c>n</c> for which all coefficients are < /// Double.MaxValue is 1029. If the computed value exceeds Double.MaxValue, /// Double.PositiveInvinifty is returned</item> /// </list></para> /// </summary> /// <param name="n">the size of the set</param> /// <param name="k">the size of the subsets to be counted</param> /// <returns><c>n choose k</c></returns> /// <exception cref="NotPositiveException"> if <c>n < 0</c>.</exception> /// <exception cref="NumberIsTooLargeException"> if <c>k > n</c>.</exception> /// <exception cref="MathArithmeticException"> if the result is too large to be /// represented by a double.</exception> public static double binomialCoefficientDouble(int n, int k) { CombinatoricsUtils.checkBinomial(n, k); if ((n == k) || (k == 0)) { return(1d); } if ((k == 1) || (k == n - 1)) { return(n); } if (k > n / 2) { return(binomialCoefficientDouble(n, n - k)); } if (n < 67) { return(binomialCoefficient(n, k)); } double result = 1d; for (int i = 1; i <= k; i++) { result *= (double)(n - k + i) / (double)i; } return(FastMath.floor(result + 0.5)); }
/// <summary> /// Returns the natural <c>log</c> of the <a /// href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial /// Coefficient</a>, "<c>n choose k</c>", the number of /// <c>k</c>-element subsets that can be selected from an /// <c>n</c>-element set. /// <para> /// Preconditions: /// <list type="bullet"> /// <item> <c>0 <= k <= n</c> (otherwise /// <c>IllegalArgumentException</c> is thrown)</item> /// </list></para> /// </summary> /// <param name="n">the size of the set</param> /// <param name="k">the size of the subsets to be counted</param> /// <returns><c>n choose k</c></returns> /// <exception cref="NotPositiveException"> if <c>n < 0</c>.</exception> /// <exception cref="NumberIsTooLargeException"> if <c>k > n</c>.</exception> /// <exception cref="MathArithmeticException"> if the result is too large to be /// represented by a double.</exception> public static double binomialCoefficientLog(int n, int k) { CombinatoricsUtils.checkBinomial(n, k); if ((n == k) || (k == 0)) { return(0); } if ((k == 1) || (k == n - 1)) { return(FastMath.log(n)); } /* * For values small enough to do exact integer computation, * return the log of the exact value */ if (n < 67) { return(FastMath.log(binomialCoefficient(n, k))); } /* * Return the log of binomialCoefficientDouble for values that will not * overflow binomialCoefficientDouble */ if (n < 1030) { return(FastMath.log(binomialCoefficientDouble(n, k))); } if (k > n / 2) { return(binomialCoefficientLog(n, n - k)); } /* * Sum logs for values that could overflow */ double logSum = 0; // n!/(n-k)! for (int i = n - k + 1; i <= n; i++) { logSum += FastMath.log(i); } // divide by k! for (int i = 2; i <= k; i++) { logSum -= FastMath.log(i); } return(logSum); }
/// <summary> /// Compute n!, the <a href="http://mathworld.wolfram.com/Factorial.html"> /// factorial</a> of <c>n</c> (the product of the numbers 1 to n), as a /// <c>double</c>. /// The result should be small enough to fit into a <c>double</c>: The /// largest <c>n</c> for which <c>n! < Double.MaxValue</c> is 170. /// If the computed value exceeds <c>Double.MaxValue</c>, /// <c>Double.PositiveInfinity</c> is returned. /// </summary> /// <param name="n">Argument.</param> /// <returns><c>n!</c></returns> /// <exception cref="NotPositiveException"> if <c>n < 0</c>.</exception> public static double factorialDouble(int n) { if (n < 0) { throw new NotPositiveException <Int32>(new LocalizedFormats("FACTORIAL_NEGATIVE_PARAMETER"), n); } if (n < 21) { return(FACTORIALS[n]); } return(FastMath.floor(FastMath.exp(CombinatoricsUtils.factorialLog(n)) + 0.5)); }
public static long stirlingS2(int n, int k) { return(CombinatoricsUtils.stirlingS2(n, k)); }
public static long binomialCoefficient(int n, int k) { return(CombinatoricsUtils.binomialCoefficient(n, k)); }
public static double factorialLog(int n) { return(CombinatoricsUtils.factorialLog(n)); }
public static long factorial(int n) { return(CombinatoricsUtils.factorial(n)); }
public static double binomialCoefficientLog(int n, int k) { return(CombinatoricsUtils.binomialCoefficientLog(n, k)); }
/// <summary> /// Returns an exact representation of the <a /// href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial /// Coefficient</a>, "<c>n choose k</c>", the number of /// <c>k</c>-element subsets that can be selected from an /// <c>n</c>-element set. /// <para> /// Preconditions: /// <list type="bullet"> /// <item> <c>0 <= k <= n</c> (otherwise /// <c>MathIllegalArgumentException</c> is thrown)</item> /// <item> The result is small enough to fit into a <c>long</c>. The /// largest value of <c>n</c> for which all coefficients are /// <c> < Int64.MaxValue</c> is 66. If the computed value exceeds /// <c>Int64.MaxValue</c> an <c>ArithMeticException</c> is /// thrown.</item> /// </list></para> /// </summary> /// <param name="n">the size of the set</param> /// <param name="k">the size of the subsets to be counted</param> /// <returns><c>n choose k</c></returns> /// <exception cref="NotPositiveException"> if <c>n < 0</c>.</exception> /// <exception cref="NumberIsTooLargeException"> if <c>k > n</c>.</exception> /// <exception cref="MathArithmeticException"> if the result is too large to be /// represented by a long integer.</exception> public static long binomialCoefficient(int n, int k) { CombinatoricsUtils.checkBinomial(n, k); if ((n == k) || (k == 0)) { return(1); } if ((k == 1) || (k == n - 1)) { return(n); } // Use symmetry for large k if (k > n / 2) { return(binomialCoefficient(n, n - k)); } // We use the formula // (n choose k) = n! / (n-k)! / k! // (n choose k) == ((n-k+1)*...*n) / (1*...*k) // which could be written // (n choose k) == (n-1 choose k-1) * n / k long result = 1; if (n <= 61) { // For n <= 61, the naive implementation cannot overflow. int i = n - k + 1; for (int j = 1; j <= k; j++) { result = result * i / j; i++; } } else if (n <= 66) { // For n > 61 but n <= 66, the result cannot overflow, // but we must take care not to overflow intermediate values. int i = n - k + 1; for (int j = 1; j <= k; j++) { // We know that (result * i) is divisible by j, // but (result * i) may overflow, so we split j: // Filter out the gcd, d, so j/d and i/d are integer. // result is divisible by (j/d) because (j/d) // is relative prime to (i/d) and is a divisor of // result * (i/d). long d = ArithmeticUtils.gcd(i, j); result = (result / (j / d)) * (i / d); i++; } } else { // For n > 66, a result overflow might occur, so we check // the multiplication, taking care to not overflow // unnecessary. int i = n - k + 1; for (int j = 1; j <= k; j++) { long d = ArithmeticUtils.gcd(i, j); result = ArithmeticUtils.mulAndCheck(result / (j / d), i / d); i++; } } return(result); }