Java的阶乘函数返回值为0

3

我写了一个简单的函数来计算一个数的阶乘,但是从34开始返回0。实际上应该是从51开始返回0。

   public class Métodos {
       public int factorial (int numero ){

          if ((numero <0)||(numero>50)){

           return 0;        
          } 

          else if ((numero == 0)||(numero == 1)){

           return 1;   
          }

          else{

           return numero * factorial(numero -1); 


          }

    }




    }

谢谢!

编辑:

好的,我该怎么检查?因为它说int无法转换为bigInteger。

 public static void main(String[] args) {
        // TODO code application logic here
         Métodos metod = new Métodos();
         System.out.print("El resultado es : " + metod.factorial(-12)+ "\n");
         System.out.print("El resultado es : " + metod.factorial(-1)+ "\n");
         System.out.print("El resultado es : " + metod.factorial(0)+ "\n");
         System.out.print("El resultado es : " + metod.factorial(1)+ "\n");
         System.out.print("El resultado es : " + metod.factorial(5)+ "\n");
         System.out.print("El resultado es : " + metod.factorial(51)+ "\n");
         System.out.print("El resultado es : " + metod.factorial(520)+ "\n");
    }
4个回答

6
34的阶乘约为3*1038,这个数字太大了,超出了int类型的范围(最大值为2*109),即便是long类型也无法容纳。如果需要计算如此大的阶乘,应该使用BigInteger类。该类的对象可以保存任意大小的整数值。请注意,操作不会使用中缀运算符,而是使用方法。具体用法请参考BigInteger文档。
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));
    }
}

谢谢。我编辑了问题。你能看一下吗? - user3325719

4
Factorials become very large very quickly. The int data type is insufficient for storing the resulting huge numbers. Only up to 12! can be stored in an int. By switching to long, you can store up to 20!. However, if you need to go beyond that, you will need to use BigInteger.
The reason why every result becomes 0 starting at 34! is due to its size. 34! is:
295232799039604140847618609643520000000

这个数字的质因数是:

232 × 315 × 57 × 74 × 113 × 132 × 172 × 19 × 23 × 29 × 31

请注意,这个质因数分解有32个2。这意味着当用二进制表示时,该数字以32个零结尾。
1101111000011011110001001101000110011110111111001010110010000010
0100010001011101101001110101101100000000000000000000000000000000

由于一个int只有32位,它只能保存那个数字的低32位,而这些位都是0,所有位都为0的int表示数值0。

(我之前提到它实际上会更早出现错误;在12!之后,正确的结果将使int溢出。然而,乘法的一个简单事实是,当两个数相乘时,数字不能影响较低位置的结果数字;只有同一位置或更高位置的数字可以影响结果。例如,将任意两个以4结尾的长数字相乘。结果必须以6结尾,无论完整数字是什么。这意味着即使阶乘计算溢出了int,所有低32位仍然是正确的!)

在34!之后,每个阶乘的质因数分解中至少有32个2(因为它是前一个阶乘的简单倍数),因此当正确的值被截断以适应int时,它们都将变成0。另一种看待它的方式是,在34!之后,每个阶乘都被计算为0,因为它只是先前计算的0的倍数。


谢谢。我编辑了问题。你能看一下吗? - user3325719

1

1- 我是一名以葡萄牙语为母语的人,请遵循我的建议:用英文编写代码。这样世界上的人们会更容易阅读,当你参加会议时,你的方法将会有像getSomething()或setSomething(something)这样的名称。

2- 关于您的问题。请尝试:

for (int i = 0 ; i < 60; i++){
    System.out.println(i + " " + factorial(i));
}

你会发现在12左右开始出现奇怪的值,因为Java中的int类型限制为2^31-1,你已经溢出了:http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html 你可以尝试使用long类型。但是在51之前也会溢出。
你需要使用BigInteger类来处理任意值。
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)));
    }
}

谢谢你的建议。 - user3325719

1

Java中的int是一种原始有符号类型,存储在32位中,这意味着它的有效范围为-231到231-1(另请参见Integer.MIN_VALUEInteger.MAX_VALUE)。在Java 8+中,您可以使用lambda表达式计算阶乘,并将int值的范围从2n进行映射到BigInteger,然后使用乘法对值进行规约;例如:

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));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接