/** * Computes the factorial of a number (n!). * * @param n Number. * @return Result. */ public static double Factorial(int n) { if (fcache == null) { // Initialize factorial cache fcache = new double[33]; fcache[0] = 1; fcache[1] = 1; fcache[2] = 2; fcache[3] = 6; fcache[4] = 24; ftop = 4; } if (n < 0) { try { throw new ArithmeticException("Argument cannot be negative."); } catch (Exception e) { e.printStackTrace(); } } if (n > 32) { // Return Gamma approximation using exp(gammaln(n+1)), // which for some reason is faster than gamma(n+1). return Math.exp(Gamma.Log(n + 1.0)); } else { // Compute in the standard way, but use the // factorial cache to speed up computations. while (ftop < n) { int j = ftop++; fcache[ftop] = fcache[j] * ftop; } return fcache[n]; } }
/** * Returns the log factorial of a number (ln(n!)) * * @param n Number. * @return Result. */ public static double LogFactorial(int n) { if (lnfcache == null) lnfcache = new double[101]; if (n < 0) { // Factorial is not defined for negative numbers. try { throw new ArithmeticException("Argument cannot be negative."); } catch (Exception e) { e.printStackTrace(); } } if (n <= 1) { // Factorial for n between 0 and 1 is 1, so log(factorial(n)) is 0. return 0.0; } if (n <= 100) { // Compute the factorial using ln(gamma(n)) approximation, using the cache // if the value has been previously computed. return (lnfcache[n] > 0) ? lnfcache[n] : (lnfcache[n] = Gamma.Log(n + 1.0)); } else { // Just compute the factorial using ln(gamma(n)) approximation. return Gamma.Log(n + 1.0); } }