/**
   * 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);
    }
  }