Combination and factorial Combinations is how many ways to take k elements from n element.  Combination is different from permutation in that order does not matter in combination. Combination is used a lot in poker calculations. Those are combinations used a lot in poker that I know are correct. 

In Fast there are a number of terms that cancel out so I avoid them.

Please review for style and efficiency.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Numerics;

namespace CodeReview01
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 2; i &lt;= 10; i++)
            {
                BigInteger factorial = Factorial(i);
                Debug.WriteLine($"factorial({i}) =  {factorial}");
            }
            Debug.WriteLine("");
            int n = 3;
            int k = 2;
            Debug.WriteLine($"Combin({n}, {k}) = {CombinationFact(n, k)}");
            Debug.WriteLine($"Combin({n}, {k}) = {CombinationFast(n, k)}");
            n = 4;
            k = 2;
            Debug.WriteLine($"Combin({n}, {k}) = {CombinationFact(n, k)}");
            Debug.WriteLine($"Combin({n}, {k}) = {CombinationFast(n, k)}");
            n = 45;
            k = 2;
            Debug.WriteLine($"Combin({n}, {k}) = {CombinationFact(n, k)}");
            Debug.WriteLine($"Combin({n}, {k}) = {CombinationFast(n, k)}");         
            n = 52;
            k = 2;
            Debug.WriteLine($"Combin({n}, {k}) = {CombinationFact(n, k)}");
            Debug.WriteLine($"Combin({n}, {k}) = {CombinationFast(n, k)}");
            n = 52;
            k = 5;
            Debug.WriteLine($"Combin({n}, {k}) = {CombinationFact(n, k)}");
            Debug.WriteLine($"Combin({n}, {k}) = {CombinationFast(n, k)}");
            n = 52;
            k = 7;
            Debug.WriteLine($"Combin({n}, {k}) = {CombinationFact(n, k)}");
            Debug.WriteLine($"Combin({n}, {k}) = {CombinationFast(n, k)}");
            Debug.WriteLine("");
        }

        public static BigInteger Factorial (int n)
        {
            if(n &lt; 1)
            {
                throw new IndexOutOfRangeException();
            }
            BigInteger factorial = 1;
            for(int i = 2; i &lt;= n; i++)
            {
                factorial *= i;
            }
            return factorial;
        }
        public static int CombinationFact(int n, int k)
        {
            if(n &lt; k)
            {
                throw new IndexOutOfRangeException();
            }
            if (n &lt; 1 | k &lt; 1)
            {
                throw new IndexOutOfRangeException();
            }
            if (n == k)
            {
                return 1;
            }
            int combination = (int)(Factorial(n) / Factorial(k) / Factorial(n - k)); 
            return combination;
        }
        public static int CombinationFast(int n, int k)
        {
            BigInteger combination = 1;
            //   n * (n-1) * (n-2) * (n-3) * (n - 4) ... 2 * 1/ 
            // / k * (k-1) ... * 2 * 1 
            // / (n-k) * ... 2 * 1_
            for(int i = k+1; i &lt;=n; i++)
            {
                combination *= i;
            }
            BigInteger denominator = 1;
            for (int i = 2; i &lt;= (n - k); i++)
            {
                denominator *= i;
            }
            combination /= denominator;
            return (int)combination;
        }
    }
}
int is IMO not an appropriate type in this domain. I would use ulong or maybe BigInteger

If you for instance run the following test, both CombinationFact() and CombinationFast() runs out of range:

  n = 52;
  k = 9;
  Console.WriteLine($"Combin({n}, {k}) = {CombinationFact(n, k)}");
  Console.WriteLine($"Combin({n}, {k}) = {CombinationFast(n, k)}");




I would use throw new ArgumentOutOfRangeException(nameof(n));

instead of throw new IndexOutOfRangeException();



You don't need the extra variable combinations:


  int combination = (int)(Factorial(n) / Factorial(k) / Factorial(n - k)); 
              return combination;


Just return the result of the calculation:

  return (int)(Factorial(n) / Factorial(k) / Factorial(n - k)); 




Both of your algorithms is rather limited in use due to the int-conversion, but you could change the fast version to something like:

public ulong CombinationFast(ulong n, ulong k)
{
  ulong count = n;

  for (ulong x = 1; x &lt;= k - 1; x++)
  {
    count *= (n - x);
    count /= x;
  }

  return count / k;
}


Update

Because 10!/(4!(10-4)!) == (10!/6!(10-6)!) it is possible to optimize the calculation for k &gt; n/2:

public ulong CombinationFast(ulong n, ulong k)
{
  if (k &gt; n / 2)
    k = n - k;

  ulong count = n;

  for (ulong x = 1; x &lt;= k - 1; x++)
  {
    count *= (n - x);
    count /= x;
  }

  return count / k;
}


The above algorithms is an implementation of this expression.

A more literal version should maybe be:

public ulong CombinationFast(ulong n, ulong k)
{
  if (k &gt; n / 2)
    k = n - k;

  ulong count = 1;

  for (ulong x = 0; x &lt; k; x++)
  {
    count *= (n - x);
    count /= (x + 1);
  }

  return count;
}