import java.math.BigInteger ;
public class Factorial_J_BigInteger {
  public static BigInteger iterative ( final BigInteger n ) {
    if ( n.compareTo ( BigInteger.ZERO ) < 0 ) { throw new FactorialIllegalArgumentException ( "Parameter must be a non-negative integer." ) ; }
    BigInteger total = BigInteger.ONE ;
    if ( n.compareTo ( BigInteger.ONE )  > 0 ) {
      BigInteger i = BigInteger.ONE ;
      while ( i.compareTo ( n ) <= 0 ) { total = total.multiply ( i ) ; i = i.add ( BigInteger.ONE ) ; }
    }
    return total ;
  }
  public static BigInteger iterative ( final long n ) { return iterative ( new BigInteger ( Long.toString ( n ) ) ) ; }
  public static BigInteger recursive ( final BigInteger n ) {
    if ( n.compareTo ( BigInteger.ZERO ) < 0 ) { throw new FactorialIllegalArgumentException ( "Parameter must be a non-negative integer." ) ; }
    return n.compareTo ( BigInteger.ONE ) <= 0 ? BigInteger.ONE : n.multiply ( recursive ( n.subtract ( BigInteger.ONE ) ) ) ;
  }
  public static BigInteger recursive ( final long n ) { return recursive ( new BigInteger ( Long.toString ( n ) ) ) ; }
  private static BigInteger iterate ( final BigInteger n , final BigInteger result ) {
    return n.compareTo ( BigInteger.ONE ) <= 0 ? result : iterate ( n.subtract ( BigInteger.ONE ) , result.multiply ( n ) ) ;
  }
  public static BigInteger tailRecursive ( final BigInteger n ) {
    if ( n.compareTo ( BigInteger.ZERO ) < 0 ) { throw new FactorialIllegalArgumentException ( "Parameter must be a non-negative integer." ) ; }
    return n.compareTo ( BigInteger.ONE ) <= 0 ? BigInteger.ONE : iterate ( n , BigInteger.ONE ) ;
  }
  public static BigInteger tailRecursive ( final long n ) { return tailRecursive ( new BigInteger ( Long.toString ( n ) ) ) ; }
}
