Definition
- Factorial (N!) – the product of all positive integers from 1 up to N, growing extremely fast.
- Base case –
fact(0) = 1returns the known answer directly and stops the recursion. - Recursive case –
fact(n) = n * fact(n-1)reduces the problem by one on every call until it reaches zero. - Overflow danger – 13! exceeds
intrange and 21! exceedslongrange, so financial code usesBigInteger. - Stack depth – each call adds a frame; for very large N an iterative version avoids
StackOverflowError.
Suppose National Bank of India is arranging N different cheques in a row and wants to know how many different orders are possible. For the first slot there are N choices, for the next slot N minus one choices, and so on down to one. The total number of arrangements is N!. Rajesh asks Pankaj: the arrangements of N cheques equal N times the arrangements of the remaining N minus one cheques, and the arrangements of zero cheques is just one, the empty arrangement.
Understanding the Concepts
What is factorial?
The factorial of a non-negative integer N, written N!, is the product of all positive integers from 1 up to N. By definition, 0! equals 1 because the product of no numbers is the multiplicative identity.
- 0! = 1
- 1! = 1
- 5! = 5 * 4 * 3 * 2 * 1 = 120
- 10! = 3628800
How does the recursive definition work?
The mathematical definition is already recursive: fact(0) = 1 is the base case and fact(n) = n * fact(n-1) is the recursive case. Each call reduces N by one, so we are guaranteed to reach zero and stop.
package com.bank.service;
import java.math.BigInteger;
public class FactorialCalculator {
public static BigInteger factorial(int n) {
if (n < 0) {
throw new IllegalArgumentException("Factorial not defined for negative: " + n);
}
if (n == 0) {
return BigInteger.ONE; // base case
}
return BigInteger.valueOf(n).multiply(factorial(n - 1)); // recursive case
}
public static void main(String[] args) {
// How many ways can Rajesh arrange 5 cheques?
System.out.println("5! = " + factorial(5));
System.out.println("0! = " + factorial(0));
System.out.println("20! = " + factorial(20));
}
}
5! = 120
0! = 1
20! = 2432902008176640000
Why does overflow matter in banking?
Factorials explode: 13! already exceeds the maximum value of a 32-bit int (2,147,483,647), and 21! exceeds a 64-bit long. In a financial system, using the wrong type silently produces a garbage negative number, which is dangerous.
// Wrong: int overflows silently
int result = 1;
for (int i = 1; i <= 13; i++) result *= i;
System.out.println(result); // 1932053504 (WRONG, should be 6227020800)
// Correct: BigInteger never overflows
System.out.println(factorial(13)); // 6227020800
How is recursive different from iterative?
| Feature | Recursive | Iterative |
|---|---|---|
| Mirrors math definition | Yes, directly | No, uses a loop |
| Stack usage | O(n) frames | O(1) |
| Risk of StackOverflowError | Yes, for large N | No |
| Readability | Very clear | Slightly more code |
| Performance | Overhead per call | Slightly faster |
// Iterative version: same result, no stack risk
public static BigInteger factorialIterative(int n) {
if (n < 0) throw new IllegalArgumentException("Negative input");
BigInteger result = BigInteger.ONE;
for (int i = 2; i <= n; i++) {
result = result.multiply(BigInteger.valueOf(i));
}
return result;
}
What happens with negative input?
Factorial is undefined for negative numbers. The method must validate and reject.
try {
factorial(-1);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage()); // Factorial not defined for negative: -1
}
What are edge cases?
factorial(0)returns 1, the base case.factorial(1)returns 1, since1 * fact(0) = 1 * 1 = 1.- Very large N (e.g., 10000) works with BigInteger but would overflow the stack in the recursive version. Use the iterative version for large N.
What are common mistakes?
// Wrong: missing base case causes infinite recursion
public static BigInteger factorialBroken(int n) {
return BigInteger.valueOf(n).multiply(factorialBroken(n - 1));
// Never stops! StackOverflowError
}
// Wrong: using int or long for the result
long result = 1;
for (int i = 1; i <= 25; i++) result *= i; // overflows past 20!
// Correct: BigInteger with proper base case
public static BigInteger factorialCorrect(int n) {
if (n == 0) return BigInteger.ONE;
return BigInteger.valueOf(n).multiply(factorialCorrect(n - 1));
}
What should a senior engineer know?
A senior engineer chooses between recursive and iterative based on the expected range of N. For teaching, interviews, and small N the recursive version is preferred because it reads like the mathematical definition. For production with potentially large N, the iterative version avoids the StackOverflowError risk.
Tail-call optimization would make recursion as efficient as iteration, but the JVM does not guarantee tail-call optimization, so in Java you cannot rely on it. Kotlin and Scala offer tailrec annotations for this.
Caching computed factorials is another senior optimization. If the same factorials are requested repeatedly, store them in a lookup table and return cached values.
What are common interview follow-up questions?
- How would you compute the number of trailing zeros in N!?
- Can you write factorial using Java Streams?
- What is the time complexity of computing N! with BigInteger?
Visual Overview
factorial(5)
│
▼
5 * factorial(4)
│
▼
4 * factorial(3)
│
▼
3 * factorial(2)
│
▼
2 * factorial(1)
│
▼
1 * factorial(0)
│
▼
return 1 ← base case
return 1 * 1 = 1
return 2 * 1 = 2
return 3 * 2 = 6
return 4 * 6 = 24
return 5 * 24 = 120
Key Takeaway
Factorial of N is the product of all positive integers from one up to N, and it has a naturally recursive definition. The base case is that the factorial of zero is one, and the recursive case is that the factorial of N equals N multiplied by the factorial of N minus one. In code the base case stops the recursion by returning one directly, and the recursive case reduces the problem by one on every call until it reaches zero.
The most important thing in real banking code is the choice of data type. Factorials grow explosively: thirteen factorial already overflows a thirty-two bit integer and twenty-one factorial overflows a sixty-four bit long. In a financial system an overflow silently produces a wrong, often negative, number, and that could corrupt a calculation without anyone noticing. So in a risk-scenario engine at National Bank of India, factorials are computed with BigInteger, which grows to any size and never overflows, and the input is validated to reject negative numbers because a negative factorial is undefined.
The senior-level nuance is that recursion costs a stack frame per call, so for a very large N the iterative loop is safer and avoids a StackOverflowError. The recursive form is elegant and correct for moderate inputs, but in production the form is chosen based on the expected range of N and whether the JVM stack can accommodate the depth.
Remember one sentence: factorial is N times factorial of N minus one with a base case of one at zero, and in banking always use BigInteger because int and long overflow silently.
---