不返回堆栈但也不返回结果的巨人数的阶乘(JAVA)
EDIT:我特别想把这个问题看作是一个尾部递归函数。使用迭代解决方案不是一种选择。 我正在尝试组合一个阶乘计算器,只要结果小于2^2147483647,它就可以处理任何整数作为输入(因为我使用BigInteger) 我遇到了这样一个问题:阶乘的结果有时只打印为输出,尽管我不相信我已经超过了堆栈的容量。对于~8000以下的值(估计值,每次执行时是否不相同?),它似乎始终有效,但对于~8000到~31400之间的值,它间歇性地不打印任何内容(随着数字的增加,显示空白返回的频率越来越高?) 有一次我得到13947作为堆栈溢出之前处理的最高整数,另一次是12000。我认为,至少在执行过程中,可变堆栈状态可以起到很大作用(因为每次都会接受用户输入并进行更改),但我是一个相当新的程序员,我对某些事情的理论理解可能不稳定,所以我不确定 有人知道为什么代码可能没有为某些高值打印任何内容吗?我最好的猜测是不返回堆栈但也不返回结果的巨人数的阶乘(JAVA),java,recursion,jvm,biginteger,tail-recursion,Java,Recursion,Jvm,Biginteger,Tail Recursion,EDIT:我特别想把这个问题看作是一个尾部递归函数。使用迭代解决方案不是一种选择。 我正在尝试组合一个阶乘计算器,只要结果小于2^2147483647,它就可以处理任何整数作为输入(因为我使用BigInteger) 我遇到了这样一个问题:阶乘的结果有时只打印为输出,尽管我不相信我已经超过了堆栈的容量。对于~8000以下的值(估计值,每次执行时是否不相同?),它似乎始终有效,但对于~8000到~31400之间的值,它间歇性地不打印任何内容(随着数字的增加,显示空白返回的频率越来越高?) 有一次我得
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;
}