简体   繁体   English

递归的堆栈溢出异常

[英]Stack overflow exception with recursion

I am trying to make a program which calculates double factorial ( example - n=3, => (3!)! = 6! = 720 ) but i have some issues with recursion bottom and i have stack overflow exception. 我正在尝试制作一个计算双阶乘的程序( 例如-n = 3,=>(3!)!= 6!= 720 ),但是递归底部存在一些问题,并且堆栈溢出异常。

public static long df(long n) {
    if (n == 1) {
        return 1;
    } else {
        return df(n * df(n - 1));
    }
}

public static void main(String[] args) {
    System.out.println(df(3));
}

You're encountering an infinite loop with df(n * df(n - 1)); 您正在遇到df(n * df(n - 1));的无限循环df(n * df(n - 1));

n * df(n-1) will compute the factorial, and you're inadvertently feeding your answer back into the recursive method, causing it to go on forever n * df(n-1)将计算阶乘,并且您无意中将答案反馈到递归方法中,从而使它永远存在

Change 更改

return df(n * df(n - 1));

to

return n * df(n - 1);

and you should get the correct result for factorials 而且您应该获得阶乘的正确结果


Once you have this working recursive factorial method, it becomes much easier to create a double factorial by just using df(df(3)) 一旦有了这种有效的递归阶乘方法,只需使用df(df(3))轻松创建双重阶乘

I think you should use mutual recursion with the help of factorial. 我认为您应该在阶乘的帮助下使用相互递归。

The general g-factorial function can compose factorial g times: 一般的g阶乘函数可以构成g阶乘:

public static long gf(long n, long g) {
    if (g == 1){
        return fact(n);
    }
    return fact(gf(n, g - 1));
}

The specific double factorial can be gf(n, 2) : 具体的双阶乘可以是gf(n, 2)

public static long df(long n) {
    return gf(n, 2);
}

And the factorial helper function: 和阶乘助手功能:

public static long fact(long n) {
    if (n == 1) {
        return 1;
    } else {
        return n * fact(n - 1);
    }
}

Now test: 现在测试:

public static void main(String[] args) {
    System.out.println(df(3));
}

We can do: 我们可以做的:

public static long factorial(long n) {
    return (n <= 1) ? 1 : n * factorial(n - 1);
}

public static long twice_factorial(long n) {
    return factorial(factorial(n));
}

And, if needed, with some trickery turn this into a single method: 并且,如果需要,可以通过一些技巧将其转换为单个方法:

public static long twice_factorial(long n) {

    return new Object() {
        long factorial(long n) {
            return (n <= 1) ? 1 : n * factorial(n - 1);
        }

        long twice_factorial(long n) {
            return factorial(factorial(n));
        }
    }.twice_factorial(n);
}

But this is a useless function as it's only good for n < 4 -- once we reach (4!)!, we exceed the limit of Java's long type: 但这是一个无用的函数,因为它仅对n <4有用-一旦达到(4!)!,我们将超出Java的long类型的限制:

(4!)! = 24! = 620,448,401,733,239,439,360,000
Java 'long' +max  = 9,223,372,036,854,755,807

If you want this function to be useful, you might use a floating approximation equation instead. 如果希望此功能有用,则可以改用浮动近似方程。 But calling approximate factorial again on an approximation probably doesn't make much sense. 但是,再次对近似值调用近似阶乘可能没有多大意义。 You'd want a floating approximation equation for the nested factorial value itself. 您需要一个嵌套阶乘值本身的浮动近似方程。

Or, we can switch to BigInteger : 或者,我们可以切换到BigInteger

import java.math.BigInteger;

public class Test {

    public static BigInteger factorial(BigInteger n) {
        return (n.compareTo(BigInteger.ONE) <= 0) ? n : n.multiply(factorial(n.subtract(BigInteger.ONE)));
    }

    public static BigInteger twice_factorial(BigInteger n) {
        return factorial(factorial(n));
    }

    public static void main(String[] args) {
        System.out.println(twice_factorial(new BigInteger(args[0])));
    }
}

USAGE 用法

> java Test 4
620448401733239439360000
>

But this only gets to (7!)! 但这只能达到(7!)! before we get java.lang.StackOverflowError ! 在我们得到java.lang.StackOverflowError之前! If we want to go further, we need to dump the recursion and compute the factorial iteratively: 如果我们想走得更远,则需要转储递归并迭代计算阶乘:

public static BigInteger factorial(BigInteger n) {
    BigInteger result = BigInteger.ONE;

    while (n.compareTo(BigInteger.ONE) > 0) {
        result = result.multiply(n);

        n = n.subtract(BigInteger.ONE);
    }

    return result;
}

USAGE 用法

> java Test 8
34343594927610057460299569794488787548168370492599954077788679570543951730
56532019908409885347136320062629610912426681208933917127972031183174941649
96595241192401936325236835841309623900814542199431592985678608274776672087
95121782091782285081003034058936009374494731880192149398389083772042074284
01934242037338152135699611399400041646418675870467025785609383107424869450
...
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000
> 

Firstly, define your factorial function: 首先,定义您的阶乘函数:

Via Jupyter: 通过Jupyter:

#include <iostream>
std::cout << "some output" << std::endl;

long fac(long n) {
    if( n == 1)
        return 1;
    else
        return n * fac((n-1));
}

And after define your function: 然后定义您的功能:

long double_fac(long n)
{
    long step_one = fac(n);
    return fac(step_one);
}

Factorielle-Algorythme Factorielle-Algorythme

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM