#include "factorial_gmp.h"

void factorial_iterative ( mpz_t result , const mpz_t n ) {
  mpz_t i ;
  mpz_init_set_ui ( result , 1 ) ;
  mpz_init_set_ui ( i , 2 ) ;
  while ( mpz_cmp ( i , n ) <= 0 ) {
    mpz_mul ( result , result , i ) ;
    mpz_add_ui ( i , i , 1 ) ;
  }
}

void factorial_recursive ( mpz_t result , const mpz_t n ) {
  if ( mpz_cmp_ui ( n , 1 ) <= 0 ) {
    mpz_init_set_ui ( result , 1 ) ;
  }
  else {
    mpz_t i ;
    mpz_init_set ( i , n ) ;
    mpz_sub_ui ( i , i , 1 ) ;
    factorial_recursive ( i , i ) ;
    mpz_mul ( result , n , i ) ;
   }
}

/***
 ***  The following is untested.
 ***/

static void factorial_tailRecursive_iterate ( mpz_t result , const mpz_t n ) {
  if ( mpz_cmp_ui ( n , 1 ) <= 0 ) { return ; }
  else {
    mpz_t i ;
    mpz_mul ( result , result , n ) ;
    mpz_init_set ( i , n ) ;
    mpz_sub_ui ( i , i , 1 ) ;
    factorial_tailRecursive_iterate ( result , i ) ;
  }
}

void factorial_tailRecursive ( mpz_t result , const mpz_t n ) {
  if ( mpz_cmp_ui ( n , 1 ) <= 0 ) { mpz_init_set_ui ( result , 1 ) ; }
  else {
    mpz_t i ;
    mpz_init_set_ui ( i , 1 ) ;
    factorial_tailRecursive_iterate ( i , n ) ; }
}
