Example usage for org.apache.commons.math3.util ArithmeticUtils mulAndCheck

List of usage examples for org.apache.commons.math3.util ArithmeticUtils mulAndCheck

Introduction

In this page you can find the example usage for org.apache.commons.math3.util ArithmeticUtils mulAndCheck.

Prototype

public static long mulAndCheck(long a, long b) throws MathArithmeticException 

Source Link

Document

Multiply two long integers, checking for overflow.

Usage

From source file:org.gitools.analysis.groupcomparison.format.math33Preview.CombinatoricsUtils.java

/**
 * Returns an exact representation of the <a
 * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial
 * Coefficient</a>, "{@code n choose k}", the number of
 * {@code k}-element subsets that can be selected from an
 * {@code n}-element set./*from w  w w  .  j  av  a  2 s .c  o  m*/
 * <p>
 * <Strong>Preconditions</strong>:
 * <ul>
 * <li> {@code 0 <= k <= n } (otherwise
 * {@code IllegalArgumentException} is thrown)</li>
 * <li> The result is small enough to fit into a {@code long}. The
 * largest value of {@code n} for which all coefficients are
 * {@code  < Long.MAX_VALUE} is 66. If the computed value exceeds
 * {@code Long.MAX_VALUE} an {@code ArithMeticException} is
 * thrown.</li>
 * </ul></p>
 *
 * @param n the size of the set
 * @param k the size of the subsets to be counted
 * @return {@code n choose k}
 * @throws NotPositiveException      if {@code n < 0}.
 * @throws NumberIsTooLargeException if {@code k > n}.
 * @throws MathArithmeticException   if the result is too large to be
 *                                   represented by a long integer.
 */
public static long binomialCoefficient(final int n, final int k)
        throws NotPositiveException, NumberIsTooLargeException, MathArithmeticException {
    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).
            final 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++) {
            final long d = ArithmeticUtils.gcd(i, j);
            result = ArithmeticUtils.mulAndCheck(result / (j / d), i / d);
            i++;
        }
    }
    return result;
}