不返回堆栈但也不返回结果的巨人数的阶乘(JAVA)

不返回堆栈但也不返回结果的巨人数的阶乘(JAVA),java,recursion,jvm,biginteger,tail-recursion,Java,Recursion,Jvm,Biginteger,Tail Recursion,EDIT:我特别想把这个问题看作是一个尾部递归函数。使用迭代解决方案不是一种选择。 我正在尝试组合一个阶乘计算器,只要结果小于2^2147483647,它就可以处理任何整数作为输入(因为我使用BigInteger) 我遇到了这样一个问题:阶乘的结果有时只打印为输出,尽管我不相信我已经超过了堆栈的容量。对于~8000以下的值(估计值,每次执行时是否不相同?),它似乎始终有效,但对于~8000到~31400之间的值,它间歇性地不打印任何内容(随着数字的增加,显示空白返回的频率越来越高?) 有一次我得

EDIT:我特别想把这个问题看作是一个尾部递归函数。使用迭代解决方案不是一种选择。

我正在尝试组合一个阶乘计算器,只要结果小于2^2147483647,它就可以处理任何整数作为输入(因为我使用BigInteger)

我遇到了这样一个问题:阶乘的结果有时只打印为输出,尽管我不相信我已经超过了堆栈的容量。对于~8000以下的值(估计值,每次执行时是否不相同?),它似乎始终有效,但对于~8000到~31400之间的值,它间歇性地不打印任何内容(随着数字的增加,显示空白返回的频率越来越高?)

有一次我得到13947作为堆栈溢出之前处理的最高整数,另一次是12000。我认为,至少在执行过程中,可变堆栈状态可以起到很大作用(因为每次都会接受用户输入并进行更改),但我是一个相当新的程序员,我对某些事情的理论理解可能不稳定,所以我不确定

有人知道为什么代码可能没有为某些高值打印任何内容吗?我最好的猜测是

  • 该结果大于2^2147483647,因此无法将其存储为BigInteger(但这并不能解释间歇性…)
  • 由于某种原因,计算时间太长,并且在计算完成之前循环仍在继续(解释了间歇性,但似乎不可能)
  • 我的EclipseIDE无法很好地将那么多数字打印到屏幕上,即使正在进行计算
  • 我不知道如何验证上述猜测。我已经阅读了BigInteger的限制,以及Eclipse的限制,但是没有找到任何可以与我的任务相比的答案

    代码如下:

    package factorielRecursiveTerminale;
    
    import java.math.BigInteger;
    import java.util.Scanner; 
    
    public class factorielRecursiveTerminale {  
    static BigInteger factoriel(BigInteger n, BigInteger m) {       //calcule le factoriel pour n'importe quel entier.  
        if (n.compareTo(BigInteger.ZERO) < 1) return m;             //    théoriquement valide pour tout entier dont n! < 2^2147483647, mais 
        return factoriel(n.subtract(BigInteger.ONE), n.multiply(m));//    limité par la capacité de la pile (à cause de la récursion). 
    }                                                               
    
    static BigInteger fact(int n) {                                 //convertir l'entree en BigInteger et lancer la recursion
        if(n < 0) {
            return BigInteger.valueOf(-1);
        }
        BigInteger b = BigInteger.valueOf(n);
        return factoriel(b, BigInteger.ONE);
    }
    
    public static void main(String[] args) {                        //demonstration
        String valeurRecu = "";
        int valeur;
        BigInteger resultat;
        System.out.println("Calcul Factoriel\n");
        while(!valeurRecu.contentEquals("q")){
            System.out.println("Entrer la valeur a calculer (q - quitter) : ");
            Scanner entree = new Scanner(System.in);
            valeurRecu = entree.nextLine();
            if (valeurRecu.contentEquals("q")) entree.close();
            else {
                try {
                    valeur = Integer.parseInt(valeurRecu);
                } catch (NumberFormatException e){  
                    System.out.println("Pas un entier. Essayer encore.\n");
                    continue;
                  } 
                try {
                    resultat = fact(valeur);
                    if(resultat.compareTo(BigInteger.valueOf(-1)) == 0) {
                        System.out.println("Valeur negative. Essayer encore.\n");
                    }
                    else System.out.println("Factoriel " + valeur + " -> " + fact(valeur) + "\n");
                }
            } catch(StackOverflowError e) {
                System.out.println("Depassement de la pile. Essayer encore.\n");
            }
            }
        }
        System.out.println("Au revoir! :)\n");
      }
    }
    

    factorial方法工作得很好,但是当超过堆栈大小时,确实会得到相对一致的溢出。我的电话数大约在9000-10000个左右。请记住,对于每个递归,n上的大值!在
    biginger
    对象中占用了相当多的空间。因此,So在堆栈跟踪的早期发生

    我建议您将这些值打印到一个文件中,而不是IDE的控制台中。这样,您就可以确定它是IDE(可能)还是程序(可能不是)。我知道对于Eclipse,控制台有一个必须设置的内部缓冲区大小以及最大行大小

    static int count;
    public static void main(String[] args) {
        count = 0;
        int n = 20000;
        BigInteger f = fact(n);
        
    }
    static BigInteger factoriel(BigInteger n, BigInteger m) {
        // calcule le factoriel pour n'importe quel entier.
        if (n.compareTo(BigInteger.ONE) < 1)
            return m; // théoriquement valide pour tout entier dont n! < 2^2147483647, mais
        
        count++;
        BigInteger f = null;
        try {
          f = factoriel(n.subtract(BigInteger.ONE), n.multiply(m));// limité par la capacité de la pile (à cause de la récursion).
        } catch(StackOverflowError e) {
            System.out.println(count);
        }
        return f;
    }
        
    static BigInteger fact(int n) { // convertir l'entree en BigInteger et lancer la recursion
        if (n < 0) {
            return BigInteger.valueOf(-1);
        }
        BigInteger b = BigInteger.valueOf(n);
        return factoriel(b, BigInteger.ONE);
    }
    
    静态整数计数;
    公共静态void main(字符串[]args){
    计数=0;
    int n=20000;
    BigInteger f=事实(n);
    }
    静态BigInteger阶乘(BigInteger n,BigInteger m){
    //重要因素的计算。
    if(n.compareTo(BigInteger.ONE)<1)
    return m;//téoriquement valide pour tout entier don!<2^2147483647,mais
    计数++;
    BigInteger f=null;
    试一试{
    F= FaseOrl(N.减去(BigTigial.1),n.乘以(m));/ /极限Ep PaéLaéde La堆(引起de Reérun)。
    }捕获(堆栈溢出错误e){
    系统输出打印项次(计数);
    }
    返回f;
    }
    静态BigInteger事实(int n){//convertir l'entre en BigInteger et lancer la递归
    if(n<0){
    返回BigInteger.valueOf(-1);
    }
    BigInteger b=BigInteger.valueOf(n);
    返回factoriel(b,biginger.ONE);
    }
    
    尽可能简单

    public static BigInteger find(BigInteger B)
        {
            BigInteger res=BigInteger.ONE;
            int b=B.intValue();
            for(int i=1;i<=b;i++)
            {
                res=res.multiply(new BigInteger(new Integer(i).toString()));
                //System.out.println(res);
            }
            return res;
        }
    
    
    公共静态BigInteger查找(BigInteger B)
    {
    biginger res=biginger.ONE;
    intb=b.intValue();
    
    对于(int i=1;i,如果需要递归方式

    public static BigInteger find(BigInteger B)
        {
            BigInteger res=BigInteger.ONE;
            if(B.compareTo(BigInteger.ZERO)==0)
                res=BigInteger.ONE;
            else
            {
                res=B.multiply(find(B.subtract(new BigInteger(new Integer(1).toString()))));
                //System.out.println(res);
            }
            return res;
        }
    
    29.9255秒 07:47:45
    11/02/20

    您能为小部分阶乘显示一些值吗?我想确保前10或20个阶乘计算正确。@标记空间确定,我将编辑以包括that@LewisMayonnaise,很可能eclipse无法将很长的行打印到控制台中(8000的阶乘有大约30K位)所以也许你应该使用文件来输出结果。@AlexRudenko很棒,解决了这个问题。看起来这些值实际上正在计算,只是没有打印到屏幕上。使用stirling近似,我估计n!<2^2147483647表示n<10^8左右。谢谢,但这并没有回答问题的任何部分。函数我写这篇文章是为了测试递归阶乘函数的限制。欢迎来到这个网站!输出:9050 12.0838 Sec 07:28:21 11/02/20递归是一个过热编辑是真的,递归有更多的开销,但我专门测试尾部递归函数。如果我真的试图优化代码,我不会使用递归。但是我这是一个不同的挑战。我发布的代码可以产生大于9050的阶乘!System.out.println(find(9050));
    public static BigInteger find(BigInteger B)
        {
            BigInteger res=BigInteger.ONE;
            if(B.compareTo(BigInteger.ZERO)==0)
                res=BigInteger.ONE;
            else
            {
                res=B.multiply(find(B.subtract(new BigInteger(new Integer(1).toString()))));
                //System.out.println(res);
            }
            return res;
        }