/** * Returns {@code n!}, that is, the product of the first {@code n} positive integers, or {@code 1} * if {@code n == 0}. * * <p><b>Warning:</b> the result takes <i>O(n log n)</i> space, so use cautiously. * * <p>This uses an efficient binary recursive algorithm to compute the factorial with balanced * multiplies. It also removes all the 2s from the intermediate products (shifting them back in at * the end). * * @throws IllegalArgumentException if {@code n < 0} */ public static BigInteger factorial(int n) { checkNonNegative("n", n); // If the factorial is small enough, just use LongMath to do it. if (n < LongMath.factorials.length) { return BigInteger.valueOf(LongMath.factorials[n]); } // Pre-allocate space for our list of intermediate BigIntegers. int approxSize = IntMath.divide(n * IntMath.log2(n, CEILING), Long.SIZE, CEILING); ArrayList<BigInteger> bignums = new ArrayList<BigInteger>(approxSize); // Start from the pre-computed maximum long factorial. int startingNumber = LongMath.factorials.length; long product = LongMath.factorials[startingNumber - 1]; // Strip off 2s from this value. int shift = Long.numberOfTrailingZeros(product); product >>= shift; // Use floor(log2(num)) + 1 to prevent overflow of multiplication. int productBits = LongMath.log2(product, FLOOR) + 1; int bits = LongMath.log2(startingNumber, FLOOR) + 1; // Check for the next power of two boundary, to save us a CLZ operation. int nextPowerOfTwo = 1 << (bits - 1); // Iteratively multiply the longs as big as they can go. for (long num = startingNumber; num <= n; num++) { // Check to see if the floor(log2(num)) + 1 has changed. if ((num & nextPowerOfTwo) != 0) { nextPowerOfTwo <<= 1; bits++; } // Get rid of the 2s in num. int tz = Long.numberOfTrailingZeros(num); long normalizedNum = num >> tz; shift += tz; // Adjust floor(log2(num)) + 1. int normalizedBits = bits - tz; // If it won't fit in a long, then we store off the intermediate product. if (normalizedBits + productBits >= Long.SIZE) { bignums.add(BigInteger.valueOf(product)); product = 1; productBits = 0; } product *= normalizedNum; productBits = LongMath.log2(product, FLOOR) + 1; } // Check for leftovers. if (product > 1) { bignums.add(BigInteger.valueOf(product)); } // Efficiently multiply all the intermediate products together. return listProduct(bignums).shiftLeft(shift); }
/** * Returns {@code n} choose {@code k}, also known as the binomial coefficient of {@code n} and * {@code k}, that is, {@code n! / (k! (n - k)!)}. * * <p><b>Warning:</b> the result can take as much as <i>O(k log n)</i> space. * * @throws IllegalArgumentException if {@code n < 0}, {@code k < 0}, or {@code k > n} */ public static BigInteger binomial(int n, int k) { checkNonNegative("n", n); checkNonNegative("k", k); checkArgument(k <= n, "k (%s) > n (%s)", k, n); if (k > (n >> 1)) { k = n - k; } if (k < LongMath.biggestBinomials.length && n <= LongMath.biggestBinomials[k]) { return BigInteger.valueOf(LongMath.binomial(n, k)); } BigInteger accum = BigInteger.ONE; long numeratorAccum = n; long denominatorAccum = 1; int bits = LongMath.log2(n, RoundingMode.CEILING); int numeratorBits = bits; for (int i = 1; i < k; i++) { int p = n - i; int q = i + 1; // log2(p) >= bits - 1, because p >= n/2 if (numeratorBits + bits >= Long.SIZE - 1) { // The numerator is as big as it can get without risking overflow. // Multiply numeratorAccum / denominatorAccum into accum. accum = accum .multiply(BigInteger.valueOf(numeratorAccum)) .divide(BigInteger.valueOf(denominatorAccum)); numeratorAccum = p; denominatorAccum = q; numeratorBits = bits; } else { // We can definitely multiply into the long accumulators without overflowing them. numeratorAccum *= p; denominatorAccum *= q; numeratorBits += bits; } } return accum .multiply(BigInteger.valueOf(numeratorAccum)) .divide(BigInteger.valueOf(denominatorAccum)); }