I made a simple function to calculate the factorial of a number but from number 34 returns 0 . It should be from number 51 .
public class Métodos {
pub
Java int
is a primitive signed type stored in 32-bits, that means it has a valid range of -231 to 231-1 (see also Integer.MIN_VALUE and Integer.MAX_VALUE). In Java 8+ you might calculate the factorial using lambdas and taking the range of int values from 2
to n
, mapping them to BigInteger
and then reduction of the values with multiplication; Like
public static BigInteger factorial(int n) {
if (n < 0) {
return BigInteger.ZERO;
}
return IntStream.rangeClosed(2, n).mapToObj(BigInteger::valueOf) //
.reduce(BigInteger.ONE, (a, b) -> a.multiply(b));
}
1- I'm a native Portuguese speaker and please follow my advice: "Write code in English." It is easier for the world to read and when you get to conventions your methods will have names like getSomething() or setSomething(something).
2- About your problem. Try:
for (int i = 0 ; i < 60; i++){
System.out.println(i + " " + factorial(i));
}
You will see that around 12 you start getting strange values because an int in java is limited to 2^31-1 and you are getting overflows: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
You can try a long. But that will also overflow long before 51.
You will have to use the BigInteger class that handles arbitrary values.
public static BigInteger factorial(BigInteger number) {
if ((number.compareTo(BigInteger.ZERO) == 0)
|| (number.compareTo(BigInteger.ONE) == 0)) {
return BigInteger.ONE;
} else {
return number.multiply(factorial(number.subtract(BigInteger.ONE)));
}
}
The factorial of 34 is about 3*1038 - it does not fit into an int
, which could hold numbers up to 2*109. The value of 34! would not fit even in a long
.
If you need to calculate factorials of such large numbers, use BigInteger class instead. Objects of that class can hold integer values of arbitrary size. Note that the operations would not be done with the infix operators, but with methods:
public BigInteger factorial (int numero ){
if (numero < 0) {
return BigInteger.ZERO;
} else if (numero==0){
return BigInteger.ONE;
} else {
return BigInteger.valueOf(numero).multiply(factorial(numero-1));
}
}
Factorials become large very fast. The int
data type you are using is too small to store the huge numbers that result. You can store up to only 12! in an int
. Switch to long
and you can store up to 20!. You will need to use BigInteger to go beyond that.
The reason why every result is 0 starting at 34!, is because 34! is:
295232799039604140847618609643520000000
The prime factors of this number are:
232 × 315 × 57 × 74 × 113 × 132 × 172 × 19 × 23 × 29 × 31
Notice that the prime factorization has 32 twos. That means that when written in binary, the number ends in exactly 32 zeros:
1101111000011011110001001101000110011110111111001010110010000010
0100010001011101101001110101101100000000000000000000000000000000
Since an int
is only 32 bits wide, it holds only the low 32 bits of that number, which are all 0, and an int
having all bits 0 represents the numeric value 0.
(I mentioned above that it actually goes wrong sooner; the correct result overflows an int
after 12!. However, it is a simple fact of multiplication that when two numbers are multiplied, digits in the numbers cannot affect result digits in lower position; only digits in same or higher position. E.g., multiply any two long numbers which both end in 4. The result must end in 6, no matter what the full numbers were. This means that even after the factorial calculation overflows the int
, all the low 32 bits are still correct!)
After 34!, every factorial will have at least 32 twos in its prime factorization (because it is a simple multiple of the previous factorial), so when the correct values are cut to fit into an int
they will all be 0. Another way of looking at it is that after 34!, every factorial is computed as 0 because it is just a multiple of the previously computed 0.