java阶乘内存不足,巨型数的阶乘不叠加,也不返回结果(JAVA)

EDIT : I am specifically trying to look at this problem as a tail-recursive function. Using an iterative solution is not an option.

I am trying to put together a factorial calculator that can handle any integer as input as long as the result is < 2^2147483647 (Since I am using BigInteger to do it).

I am running into an issue where the result of the factorial only prints as output SOMETIMES, even though I do not believe I have passed the capacity of the stack. It seems to work consistently for values under ~8000 (estimated, was not the same each execution..?), but intermittently prints nothing for values between ~8000 and ~31400 (showing blank returns increasingly often as number go up..?).

One execution I got 13947 as the highest integer handled before the stack overflow, another time it was in the 12000s. I'm thinking at least that much can be attributed to variable stack states during execution (since user input is taken and changes each time), but I am a fairly new programmer and my theoretical understanding on some things can be shaky, so I am not sure.

Does anyone know why the code might be printing nothing for some high values? My best guesses are

that result is larger than 2^2147483647, so it can't be stored as BigInteger, (but that doesn't explain the intermittent-ness...)

The calculation is somehow taking too long and the loop is continuing before calculation is finished (explains intermittent-ness but seems impossible)

My Eclipse IDE just doesn't handle printing that many digits to the screen well, even though calculation is happening.

I am not sure how to validate above guesses. I have read about the limitations of BigInteger, as well as Eclipse limitations but have not found any answer that I can compare to my task.

Here is the code :

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

}

}

Here is some sample output :

Calcul Factoriel

Entrer la valeur a calculer (q - quitter) : 0

Factoriel 0 -> 1

Entrer la valeur a calculer (q - quitter) : 1

Factoriel 1 -> 1

Entrer la valeur a calculer (q - quitter) : 2

Factoriel 2 -> 2

Entrer la valeur a calculer (q - quitter) : 3

Factoriel 3 -> 6

Entrer la valeur a calculer (q - quitter) : 4

Factoriel 4 -> 24

Entrer la valeur a calculer (q - quitter) : 10

Factoriel 10 -> 3628800

Entrer la valeur a calculer (q - quitter) : 8000

Factoriel 8000 -> 518418106.......

Entrer la valeur a calculer (q - quitter) : 9050

Factoriel 9050 -> 480838025.......

Entrer la valeur a calculer (q - quitter) : 9100

Factoriel 9100 ->

Entrer la valeur a calculer (q - quitter) : 31400

Factoriel 31400 ->

Entrer la valeur a calculer (q - quitter) : 31401

Depassement de la pile. Essayer encore.

解决方案

The factorial method works fine but you do get relatively consistent overflow when exceeding the stack size. The count for me is somewhere about 9000-10000 calls. Remember that for each recursion, the large values on n! are taking up quite a bit of space in the BigInteger object. So the SO is occurring somewhat early in stack trace.

What I suggest you do is print the values to a file instead of to the console of the IDE. That way you can determine if it is the IDE (probably) or the program (probably not). I know for Eclipse there is an internal buffer size for the console that one must set as well as a max line size.

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

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值