Factorial Program in C#: Loop, Recursion, LINQ and BigInteger

5! is 5 x 4 x 3 x 2 x 1 = 120. A factorial program in C# starts a long at 1 and multiplies it by every number from 2 to n. For 0 and 1 the loop never runs, so you get 1.

static long Factorial(int n)
{
    long result = 1;
    for (int i = 2; i <= n; i++) result *= i;
    return result;
}

In this tutorial, I’ll cover the factorial program in C# the way interviewers and CS courses ask for it: for and while loops, recursion, LINQ, overflow in int and long, BigInteger, negative input and a lookup table.

Factorial Program in C# Using a for Loop

Here’s the full .NET 10 file-based app. dotnet run ForLoop.cs runs it without a project:

Console.WriteLine($"5! = {Factorial(5)}");
Console.WriteLine($"10! = {Factorial(10)}");
Console.WriteLine($"0! = {Factorial(0)}");
try { Factorial(-3); }
catch (ArgumentOutOfRangeException ex) { Console.WriteLine(ex.Message); }

static long Factorial(int n)
{
    ArgumentOutOfRangeException.ThrowIfNegative(n);
    long result = 1;                  // 0! and 1! stay 1
    for (int i = 2; i <= n; i++)
        result *= i;
    return result;
}

Output:

5! = 120
10! = 3628800
0! = 1
n ('-3') must be a non-negative value. (Parameter 'n')
Actual value was -3.
VS Code running ForLoop.cs: a factorial program in C# with a for loop prints 5! = 120, 10! = 3628800 and 0! = 1
The for loop version returns 120 for 5! and 1 for both 0! and 1!

The loop starts at 2 because multiplying by 1 changes nothing. If the counter syntax is new to you, see the for loop in C#.

The last line is the negative-number guard. ArgumentOutOfRangeException.ThrowIfNegative(n) (.NET 8+) writes that message for you; without it, -3 quietly returns 1.

Factorial of a Number with a while Loop

Some assignments want a while loop. This one counts n down instead:

Console.WriteLine($"8! = {Factorial(8)}");

static long Factorial(int n)
{
    ArgumentOutOfRangeException.ThrowIfNegative(n);
    long result = 1;
    while (n > 1)
    {
        result *= n;
        n--;                          // count down instead of up
    }
    return result;
}

Output:

8! = 40320

It does the same multiplications in reverse. The while loop in C# post covers when each loop fits better.

Recursive Factorial in C#

Interviewers usually ask for recursion next. The method calls itself with n – 1 until the base case, 0! = 1:

foreach (int n in new[] { 0, 5, 20 })
    Console.WriteLine($"{n,2}! = {Factorial(n)}");

static long Factorial(int n)
{
    ArgumentOutOfRangeException.ThrowIfNegative(n);
    if (n == 0) return 1;             // base case
    return n * Factorial(n - 1);      // n! = n x (n - 1)!
}

Output:

 0! = 1
 5! = 120
20! = 2432902008176640000
VS Code running Recursion.cs: a recursive factorial method in C# that calls itself until the base case n == 0
The recursive method gives the same results as the loop, up to 20!

It reads exactly like the math, n! = n x (n – 1)!. If methods that return values are still fuzzy, start with functions in C#.

One catch: every call adds a stack frame, and a very deep recursion can crash the process with a StackOverflowException you can’t catch. That’s why the loop is the safer default.

Factorial with LINQ Aggregate in C#

If you like one-liners, Enumerable.Range plus Aggregate multiplies the sequence 1..n into a seed of 1:

foreach (int n in new[] { 0, 7, 15 })
{
    long f = Enumerable.Range(1, n).Aggregate(1L, (acc, x) => acc * x);
    Console.WriteLine($"{n,2}! = {f}");
}

Output:

 0! = 1
 7! = 5040
15! = 1307674368000

The 1L seed makes the accumulator a long, and it’s what 0! returns, because Range(1, 0) is empty.

Why Does My Factorial Program Print a Wrong or Negative Number?

Because factorials outgrow int and long fast. I ran the same loop with three types side by side:

using System.Numerics;

Console.WriteLine($"{"n",2} | {"int",11} | {"long",20} | BigInteger");
foreach (int n in new[] { 12, 13, 20, 21 })
{
    int i = 1; long l = 1; BigInteger b = 1;
    for (int k = 2; k <= n; k++)
    {
        i *= k; l *= k; b *= k;       // same math, three types
    }
    Console.WriteLine($"{n,2} | {i,11} | {l,20} | {b}");
}

Output:

 n |         int |                 long | BigInteger
12 |   479001600 |            479001600 | 479001600
13 |  1932053504 |           6227020800 | 6227020800
20 | -2102132736 |  2432902008176640000 | 2432902008176640000
21 | -1195114496 | -4249290049419214848 | 51090942171709440000
VS Code running OverflowLadder.cs: C# factorial with int overflows after 12!, long overflows after 20!, BigInteger stays exact
int is wrong from 13! on, long from 21! on; BigInteger keeps the real value

Look at 13!. int prints 1,932,053,504 instead of 6,227,020,800, a wrong value that looks fine. long lasts until 21!, then goes negative.

Integer math runs unchecked by default, so the high bits are silently dropped.

Catch Factorial Overflow with checked and decimal

When a wrong answer is worse than a crash, wrap the multiply in checked. decimal always throws on overflow:

foreach (int n in new[] { 20, 21 }) Show(() => $"checked long {n}! = {CheckedFactorial(n)}");
foreach (int n in new[] { 27, 28 }) Show(() => $"decimal {n}! = {DecimalFactorial(n)}");

static void Show(Func<string> calc)
{
    try { Console.WriteLine(calc()); }
    catch (OverflowException ex) { Console.WriteLine(ex.Message); }
}

static long CheckedFactorial(int n)
{
    long result = 1;
    for (int i = 2; i <= n; i++)
        result = checked(result * i);
    return result;
}

static decimal DecimalFactorial(int n)
{
    decimal result = 1;
    for (int i = 2; i <= n; i++)
        result *= i;
    return result;
}

Output:

checked long 20! = 2432902008176640000
Arithmetic operation resulted in an overflow.
decimal 27! = 10888869450418352160768000000
Value was either too large or too small for a Decimal.

checked keeps long’s 20! limit but throws OverflowException at 21!, which you can handle with try-catch in C#. decimal stretches the range to 27!, then throws at 28!.

Factorial of 100 in C# with BigInteger

For anything bigger, use System.Numerics.BigInteger. It has no fixed upper limit:

using System.Numerics;

string digits = Factorial(100).ToString();
Console.WriteLine($"100! has {digits.Length} digits");
Console.WriteLine($"Starts with: {digits[..20]}...");
Console.WriteLine($"Trailing zeros: {digits.Length - digits.TrimEnd('0').Length}");

static BigInteger Factorial(int n)
{
    ArgumentOutOfRangeException.ThrowIfNegative(n);
    BigInteger result = BigInteger.One;
    for (int i = 2; i <= n; i++)
        result *= i;
    return result;
}

Output:

100! has 158 digits
Starts with: 93326215443944152681...
Trailing zeros: 24
VS Code running BigFactorial.cs: the factorial of 100 in C# with BigInteger has 158 digits and 24 trailing zeros
100! has 158 digits and ends in 24 zeros

No built-in integer type comes close to 158 digits. BigInteger is slower than long, but it’s also what you’d use for big terms in the Fibonacci series program.

Fast Repeated Calls with a Factorial Lookup Table

If your code calls factorial over and over, say in a combinations formula, don’t recompute it. Only 0! to 20! fit in a long, so I build them once:

Console.WriteLine($"FactorialTable.Get(6)  = {FactorialTable.Get(6)}");
Console.WriteLine($"FactorialTable.Get(20) = {FactorialTable.Get(20)}");
try { FactorialTable.Get(21); }
catch (ArgumentOutOfRangeException ex) { Console.WriteLine(ex.Message); }

static class FactorialTable
{
    static readonly long[] Table = new long[21];   // 0! to 20!

    static FactorialTable()                         // runs once
    {
        Table[0] = 1;
        for (int i = 1; i < Table.Length; i++) Table[i] = Table[i - 1] * i;
    }

    public static long Get(int n)
    {
        ArgumentOutOfRangeException.ThrowIfNegative(n);
        ArgumentOutOfRangeException.ThrowIfGreaterThan(n, 20);
        return Table[n];
    }
}

Output:

FactorialTable.Get(6)  = 720
FactorialTable.Get(20) = 2432902008176640000
n ('21') must be less than or equal to '20'. (Parameter 'n')
Actual value was 21.
VS Code running LookupTable.cs: a C# factorial lookup table returns 6! and 20! instantly and rejects 21
The lookup table answers from an array and rejects 21 with ThrowIfGreaterThan

Each call is now an array read. Past 20!, cache BigInteger results in a Dictionary in C# keyed by n.

Which Factorial Method in C# Should You Use?

You needUseRange from my runs
A simple answer for classfor or while loop with long0! to 20!
The interview recursion questionRecursive method0! to 20!
An error instead of a wrong valuechecked long or decimalthrows at 21! / 28!
Big results like 100!BigInteger loop158 digits
Many calls in a loopLookup tablearray read per call

Factorial sits next to the prime number program in C# in most C# interview questions for freshers.

Still warming up for coding rounds? Try these next:

Frequently Asked Questions

How do I find the factorial of a number entered by the user in C#?

Read it with Console.ReadLine(), convert it with int.TryParse(input, out int n), and pass n to Factorial. TryParse returns false instead of throwing on bad text.

Why is 0! equal to 1?

0! is the empty product, which is 1, and it keeps n! = n x (n – 1)! true for 1!. In code, the loop doesn’t run, so the starting value of 1 comes back.

What is the largest factorial a long can hold in C#?

20!, which is 2,432,902,008,176,640,000. 21! is bigger than long.MaxValue, so it wraps to a negative number unless you use checked, decimal (up to 27!) or BigInteger.

Does .NET have a built-in factorial method?

No. There’s no Math.Factorial in .NET 10, so you write the loop yourself. For large values, use the loop with BigInteger.

Is recursion or a loop better for factorial in C#?

A loop: no extra stack frames and easier to debug. Recursion is fine for interviews and small n.