ulong iterative ( immutable ulong n ) {
  ulong total = 1 ;
  foreach ( i ; 2 .. n + 1 ) { total *= i ; }
  return total ;
}

ulong recursive ( immutable ulong n ) {
  return ( n < 2 ) ? 1 : n * recursive ( n - 1 ) ;
}

ulong tailRecursive_iterate ( immutable ulong n , immutable ulong result ) {
  //  Except of course that there is no tail recirsion in C++ so this takes serious stack space.
  return ( n < 2 ) ? result : tailRecursive_iterate ( n - 1 , result * n ) ;
}

ulong tailRecursive ( immutable ulong n ) {
  return ( n < 2 ) ? 1 : tailRecursive_iterate ( n , 1 ) ;
}

import std.conv ;

unittest {
  immutable data = [
                    [ 0L , 1L ] ,
                    [ 1L , 1L ] ,
                    [ 2L , 2L ] ,
                    [ 3L , 6L ] ,
                    [ 4L , 24L ] ,
                    [ 5L , 120L ] ,
                    [ 6L , 720L ] ,
                    [ 7L , 5040L ] ,
                    [ 8L , 40320L ] ,
                    [ 9L , 362880L ] ,
                    [ 10L , 3628800L ] ,
                    [ 11L , 39916800L ] ,
                    [ 12L , 479001600L ] ,
                    [ 13L , 6227020800L ] ,
                    [ 14L , 87178291200L ] ,
                    [ 20L , 2432902008176640000L ] ,
                    //[ 30L , 265252859812191058636308480000000L ] ,
                    //[ 40L , 815915283247897734345611269596115894272000000000L ] ,
                    ] ;
  
  foreach ( item ; data ) {
    auto result = iterative ( item[0] ) ;
    assert ( result == item[1] , "iterative ( " ~ to ! string ( item[0] ) ~ " ) = " ~ to ! string ( result ) ~ " should be " ~ to ! string ( item[1] ) ) ;
  }

  foreach ( item ; data ) {
    auto result = recursive ( item[0] ) ;
    assert ( result == item[1] , "recursive ( " ~ to ! string ( item[0] ) ~ " ) = " ~ to ! string ( result ) ~ " should be " ~ to ! string ( item[1] ) ) ;
  }

 foreach ( item ; data ) {
    auto result = tailRecursive ( item[0] ) ;
    assert ( result == item[1] , "tailRecursive ( " ~ to ! string ( item[0] ) ~ " ) = " ~ to ! string ( result ) ~ " should be " ~ to ! string ( item[1] ) ) ;
  }

}

