The largest factorial that can be computed in Java using int
is
12! = 479001600. (12! = 479,001,600).
Here is some code to test that:
public static void factorialTest () {
int i = 0, r = 1;
while (r > 0) {
r = factorial (i);
System.out.println ((i++) + "! = " + r);
}
}
public static int factorial(int n) {
if (n < 0) { return -1; }
if (n == 0 || n == 1) { return 1; }
int r = 1;
try {
for (int i = 1; i <= n; ++i) {
r = Math.multiplyExact (r, i);
}
} catch (ArithmeticException ex) {
return -2;
}
return r;
}
The method public static int factorial(int n)
returns -1
if a negative number is passed, and -2
if n
has a value that would result in the calculation of a number that can overflow an int
.
Integer calculations in Java can overflow without generating an exception. If the result of a calculation is too large, the result "wraps around". Sometimes, it is desirable to detect an overflow. To support that, the Java Math
API has a number of ~Exact
methods. These throw an ArithmeticException
when an overflow occurs.
So, the idea here is to calculate integer factorials, beginning at one, and incrementing until an overflow is caught, using try ... catch
.
It is conceivable that this could be done without using try ... catch
by testing for a result in which the result of the multiplication is less than the previous result. Since the sequence of results is strictly increasing, finding a smaller value in the result sequence would indicate a wraparound occurred. However, this isn't reliable: A calculation could wraparound and still produce an incorrect result greater than the previous result.
The largest factorial that can be computed in Java using long
is
20! = 2432902008176640000. That's 20! = 2,432,902,008,176,640,000. One can test that by changing all int
to long
in the above code.
Comment: Although Java doesn't allow unsigned
integer types to be declared, unsigned integer calculations are possible. Support for unsigned calculations includes calculations in which the result wraps around, and unsigned methods, such as toUnsignedString
. However, that seems to be irrelevant to this discussion, since the calculation of 13! would overflow an unsigned int
and the calculation of 21! would overflow an unsigned long
.
Comment: The O/P used recursion to calculate factorials. I used iteration. While I am a fan of recursion, I prefer to use iteration when an iterative solution is easy to find and implement. Recursion can use more overhead than iteration.
Comment: Optimizing compilers will sometimes change code using recursion to using iteration. That may have been the case in the O/P's code.
Output, using long
:
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
11! = 39916800
12! = 479001600
13! = 6227020800
14! = 87178291200
15! = 1307674368000
16! = 20922789888000
17! = 355687428096000
18! = 6402373705728000
19! = 121645100408832000
20! = 2432902008176640000
21! = -2