Factorial.java

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

package org.apache.commons.numbers.combinatorics;

/**
 * <a href="http://mathworld.wolfram.com/Factorial.html">Factorial of a number</a>.
 */
public final class Factorial {

    /** All long-representable factorials. */
    static final long[] FACTORIALS = {
                       1L,                  1L,                   2L,
                       6L,                 24L,                 120L,
                     720L,               5040L,               40320L,
                  362880L,            3628800L,            39916800L,
               479001600L,         6227020800L,         87178291200L,
           1307674368000L,     20922789888000L,     355687428096000L,
        6402373705728000L, 121645100408832000L, 2432902008176640000L
    };

    /** All factorials that can be represented as a double (values up to 170!). */
    private static final double[] DOUBLE_FACTORIALS = {
        1,
        1,
        2,
        6,
        24,
        120,
        720,
        5040,
        40320,
        362880,
        3628800,
        3.99168E7,
        4.790016E8,
        6.2270208E9,
        8.71782912E10,
        1.307674368E12,
        2.0922789888E13,
        3.55687428096E14,
        6.402373705728E15,
        1.21645100408832E17,
        2.43290200817664E18,
        5.109094217170944E19,
        1.1240007277776077E21,
        2.585201673888498E22,
        6.204484017332394E23,
        1.5511210043330986E25,
        4.0329146112660565E26,
        1.0888869450418352E28,
        3.0488834461171387E29,
        8.841761993739702E30,
        2.6525285981219107E32,
        8.222838654177922E33,
        2.631308369336935E35,
        8.683317618811886E36,
        2.9523279903960416E38,
        1.0333147966386145E40,
        3.7199332678990125E41,
        1.3763753091226346E43,
        5.230226174666011E44,
        2.0397882081197444E46,
        8.159152832478977E47,
        3.345252661316381E49,
        1.40500611775288E51,
        6.041526306337383E52,
        2.658271574788449E54,
        1.1962222086548019E56,
        5.502622159812089E57,
        2.5862324151116818E59,
        1.2413915592536073E61,
        6.082818640342675E62,
        3.0414093201713376E64,
        1.5511187532873822E66,
        8.065817517094388E67,
        4.2748832840600255E69,
        2.308436973392414E71,
        1.2696403353658276E73,
        7.109985878048635E74,
        4.0526919504877214E76,
        2.3505613312828785E78,
        1.3868311854568984E80,
        8.32098711274139E81,
        5.075802138772248E83,
        3.146997326038794E85,
        1.98260831540444E87,
        1.2688693218588417E89,
        8.247650592082472E90,
        5.443449390774431E92,
        3.647111091818868E94,
        2.4800355424368305E96,
        1.711224524281413E98,
        1.1978571669969892E100,
        8.504785885678623E101,
        6.1234458376886085E103,
        4.4701154615126844E105,
        3.307885441519386E107,
        2.48091408113954E109,
        1.8854947016660504E111,
        1.4518309202828587E113,
        1.1324281178206297E115,
        8.946182130782976E116,
        7.156945704626381E118,
        5.797126020747368E120,
        4.753643337012842E122,
        3.945523969720659E124,
        3.314240134565353E126,
        2.81710411438055E128,
        2.4227095383672734E130,
        2.107757298379528E132,
        1.8548264225739844E134,
        1.650795516090846E136,
        1.4857159644817615E138,
        1.352001527678403E140,
        1.2438414054641308E142,
        1.1567725070816416E144,
        1.087366156656743E146,
        1.032997848823906E148,
        9.916779348709496E149,
        9.619275968248212E151,
        9.426890448883248E153,
        9.332621544394415E155,
        9.332621544394415E157,
        9.42594775983836E159,
        9.614466715035127E161,
        9.90290071648618E163,
        1.0299016745145628E166,
        1.081396758240291E168,
        1.1462805637347084E170,
        1.226520203196138E172,
        1.324641819451829E174,
        1.4438595832024937E176,
        1.588245541522743E178,
        1.7629525510902446E180,
        1.974506857221074E182,
        2.2311927486598138E184,
        2.5435597334721877E186,
        2.925093693493016E188,
        3.393108684451898E190,
        3.969937160808721E192,
        4.684525849754291E194,
        5.574585761207606E196,
        6.689502913449127E198,
        8.094298525273444E200,
        9.875044200833601E202,
        1.214630436702533E205,
        1.506141741511141E207,
        1.882677176888926E209,
        2.372173242880047E211,
        3.0126600184576594E213,
        3.856204823625804E215,
        4.974504222477287E217,
        6.466855489220474E219,
        8.47158069087882E221,
        1.1182486511960043E224,
        1.4872707060906857E226,
        1.9929427461615188E228,
        2.6904727073180504E230,
        3.659042881952549E232,
        5.012888748274992E234,
        6.917786472619489E236,
        9.615723196941089E238,
        1.3462012475717526E241,
        1.898143759076171E243,
        2.695364137888163E245,
        3.854370717180073E247,
        5.5502938327393044E249,
        8.047926057471992E251,
        1.1749972043909107E254,
        1.727245890454639E256,
        2.5563239178728654E258,
        3.80892263763057E260,
        5.713383956445855E262,
        8.62720977423324E264,
        1.3113358856834524E267,
        2.0063439050956823E269,
        3.0897696138473508E271,
        4.789142901463394E273,
        7.471062926282894E275,
        1.1729568794264145E278,
        1.853271869493735E280,
        2.9467022724950384E282,
        4.7147236359920616E284,
        7.590705053947219E286,
        1.2296942187394494E289,
        2.0044015765453026E291,
        3.287218585534296E293,
        5.423910666131589E295,
        9.003691705778438E297,
        1.503616514864999E300,
        2.5260757449731984E302,
        4.269068009004705E304,
        7.257415615307999E306
    };

    /** Private constructor. */
    private Factorial() {
        // intentionally empty.
    }

    /**
     * Computes the factorial of {@code n}.
     *
     * @param n Argument.
     * @return {@code n!}
     * @throws IllegalArgumentException if {@code n < 0}.
     * @throws IllegalArgumentException if {@code n > 20} (the factorial
     * value is too large to fit in a {@code long}).
     */
    public static long value(int n) {
        if (n < 0 ||
            n > 20) {
            throw new CombinatoricsException(CombinatoricsException.OUT_OF_RANGE,
                                             n, 0, 20);
        }

        return FACTORIALS[n];
    }

    /**
     * Computes the factorial of {@code n}.
     *
     * <p>The result should be small enough to fit into a {@code double}: The
     * largest {@code n} for which {@code n!} does not exceed
     * {@code Double.MAX_VALUE} is 170. {@code Double.POSITIVE_INFINITY} is
     * returned for {@code n > 170}.
     *
     * @param n Argument.
     * @return {@code n!}
     * @throws IllegalArgumentException if {@code n < 0}.
     * @since 1.1
     */
    public static double doubleValue(int n) {
        if (n < 0) {
            throw new CombinatoricsException(CombinatoricsException.NEGATIVE, n);
        }
        if (n < DOUBLE_FACTORIALS.length) {
            return DOUBLE_FACTORIALS[n];
        }
        return Double.POSITIVE_INFINITY;
    }

    /**
     * Return the factorial of {@code n}.
     *
     * <p>Note: This is an internal method that exposes the tabulated factorials that can
     * be represented as a double. No checks are performed on the argument.
     *
     * @param n Argument (must be in [0, 170])
     * @return n!
     */
    static double uncheckedFactorial(int n) {
        return DOUBLE_FACTORIALS[n];
    }
}