BinomialCoefficientDouble.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.numbers.combinatorics;

  18. /**
  19.  * Representation of the <a href="http://mathworld.wolfram.com/BinomialCoefficient.html">
  20.  * binomial coefficient</a>, as a {@code double}.
  21.  * It is "{@code n choose k}", the number of {@code k}-element subsets that
  22.  * can be selected from an {@code n}-element set.
  23.  */
  24. public final class BinomialCoefficientDouble {
  25.     /** The maximum factorial that can be represented as a double. */
  26.     private static final int MAX_FACTORIAL = 170;
  27.     /** The maximum n that can be computed without overflow of a long for any m.
  28.      * {@code C(66, 33) < 2^63}. */
  29.     private static final int LIMIT_N_LONG = 66;
  30.     /** The maximum m that can be computed without overflow of a double.
  31.      * C(1030, 515) ~ 2.85e308. */
  32.     private static final int MAX_M = 514;
  33.     /** The maximum n that can be computed without intermediate overflow for any m.
  34.      * C(1020, 510) * 510 ~ 1.43e308. */
  35.     private static final int SMALL_N = 1020;
  36.     /** The maximum m that can be computed without intermediate overflow for any n.
  37.      * C(2147483647, 37) * 37 ~ 5.13e303. */
  38.     private static final int SMALL_M = 37;

  39.     /** Private constructor. */
  40.     private BinomialCoefficientDouble() {
  41.         // intentionally empty.
  42.     }

  43.     /**
  44.      * Computes the binomial coefficient.
  45.      *
  46.      * <p>The largest value of {@code n} for which <em>all</em> coefficients can
  47.      * fit into a {@code double} is 1029. Larger {@code n} may result in
  48.      * infinity depending on the value of {@code k}.
  49.      *
  50.      * <p>Any {@code min(k, n - k) >= 515} cannot fit into a {@code double}
  51.      * and will result in infinity.
  52.      *
  53.      * @param n Size of the set.
  54.      * @param k Size of the subsets to be counted.
  55.      * @return {@code n choose k}.
  56.      * @throws IllegalArgumentException if {@code n < 0}, {@code k < 0} or {@code k > n}.
  57.      */
  58.     public static double value(int n, int k) {
  59.         if (n <= LIMIT_N_LONG) {
  60.             // Delegate to the exact long result
  61.             return BinomialCoefficient.value(n, k);
  62.         }
  63.         final int m = BinomialCoefficient.checkBinomial(n, k);

  64.         if (m == 0) {
  65.             return 1;
  66.         }
  67.         if (m == 1) {
  68.             return n;
  69.         }

  70.         double result;
  71.         if (n <= MAX_FACTORIAL) {
  72.             // Small factorials are tabulated exactly
  73.             // n! / m! / (n-m)!
  74.             result = Factorial.uncheckedFactorial(n) /
  75.                      Factorial.uncheckedFactorial(m) /
  76.                      Factorial.uncheckedFactorial(n - m);
  77.         } else {
  78.             // Compute recursively using:
  79.             // (n choose m) = (n-1 choose m-1) * n / m

  80.             if (n <= SMALL_N || m <= SMALL_M) {
  81.                 // No overflow possible
  82.                 result = 1;
  83.                 for (int i = 1; i <= m; i++) {
  84.                     result *= n - m + i;
  85.                     result /= i;
  86.                 }
  87.             } else {
  88.                 if (m > MAX_M) {
  89.                     return Double.POSITIVE_INFINITY;
  90.                 }

  91.                 // Compute the initial part without overflow checks
  92.                 result = 1;
  93.                 for (int i = 1; i <= SMALL_M; i++) {
  94.                     result *= n - m + i;
  95.                     result /= i;
  96.                 }
  97.                 // Careful of overflow
  98.                 for (int i = SMALL_M + 1; i <= m; i++) {
  99.                     final double next = result * (n - m + i);
  100.                     if (next > Double.MAX_VALUE) {
  101.                         // Reverse order of terms
  102.                         result /= i;
  103.                         result *= n - m + i;
  104.                         if (result > Double.MAX_VALUE) {
  105.                             // Definite overflow
  106.                             return Double.POSITIVE_INFINITY;
  107.                         }
  108.                     } else {
  109.                         result = next / i;
  110.                     }
  111.                 }
  112.             }
  113.         }

  114.         return Math.floor(result + 0.5);
  115.     }
  116. }