Existe-t-il une méthode qui calcule une factorielle en Java?

105

Je ne l'ai pas encore trouvé. Ai-je oublié quelque chose? Je sais qu'une méthode factorielle est un programme d'exemple courant pour les débutants. Mais ne serait-il pas utile d'avoir une implémentation standard pour celle-ci à réutiliser? Je pourrais utiliser une telle méthode avec des types standard (par exemple int, long ...) et avec BigInteger / BigDecimal, aussi.

Léomord
la source

Réponses:

26

Je ne pense pas qu'il serait utile d'avoir une fonction de bibliothèque pour factorielle. Il existe de nombreuses recherches sur les implémentations factorielles efficaces. Voici quelques implémentations.

Karl le païen
la source
188
Pourquoi n'est-il pas utile d'avoir une fonction de bibliothèque pour factorielle?
midnite
17
Peu de gens ont réellement besoin de factorielles dans du code réel. Si vous le faites, vous faites probablement des mathématiques ou des statistiques avancées, auquel cas vous utiliserez probablement déjà une bibliothèque de mathématiques avec une implémentation factorielle spécialisée.
mikera
3
La fonction gamma est très utile, c'est pourquoi elle est incluse dans la bibliothèque standard C ++.
Columbo le
2
Il me semble que @KarlthePagan signifie qu'il n'est pas utile d'avoir une fonction de bibliothèque standard pour factorielle - est-ce correct?
dantiston
alors ils vous demanderaient lors de l'entretien pour voir si vous pouvez le faire vous-même * mon cas
moldave
59

Apache Commons Math a quelques méthodes factorielles dans la classe MathUtils .

Bill le lézard
la source
1
Oui. Bon produit. Il existe une implémentation de factorielle pour les nombres flottants et non plats (MathUtils.factorial (int) et MathUtils.factorialDouble (int)) ainsi que le logarithme naturel utile de n! (MathUtils.factorialLog (int))
Tomasz Błachowicz
3
c'est dans ArithmeticUtils pour le moment.
MarianP
6
ArithmeticUtils.factorial est apparemment obsolète maintenant, atm utilise CombinatoricsUtils.factorial
Victor Häggqvist
Veuillez ne pas utiliser de liens! Ils ont tendance à disparaître (comme TOUS ceux-ci l'ont fait).
SMBiggs
1
@ScottBiggs Les deux liens de la réponse fonctionnent correctement.
Bill the Lizard
40
public class UsefulMethods {
    public static long factorial(int number) {
        long result = 1;

        for (int factor = 2; factor <= number; factor++) {
            result *= factor;
        }

        return result;
    }
}

Version Big Numbers par HoldOffHunger :

public static BigInteger factorial(BigInteger number) {
    BigInteger result = BigInteger.valueOf(1);

    for (long factor = 2; factor <= number.longValue(); factor++) {
        result = result.multiply(BigInteger.valueOf(factor));
    }

    return result;
}
saroj adhikari
la source
Vous supposez également que vous voulez la factorielle d'un entier
Andrew
Cette solution doit utiliser la classe BigInteger.
Oleg Abrazhaev
2
Version Big Numbers: public static BigInteger factorial (BigInteger n) {BigInteger factorial = BigInteger.valueOf (1); for (int i = 1; i <= n.intValue (); i ++) {factorial = factorial.multiply (BigInteger.valueOf (i)); } retour factoriel; }
HoldOffHunger
23

Des factorielles nues nues sont rarement nécessaires dans la pratique. Le plus souvent, vous aurez besoin de l'un des éléments suivants:

1) diviser une factorielle par une autre, ou

2) réponse approximative en virgule flottante.

Dans les deux cas, vous seriez mieux avec des solutions personnalisées simples.

Dans le cas (1), disons, si x = 90! / 85 !, alors vous calculerez le résultat comme x = 86 * 87 * 88 * 89 * 90, sans avoir besoin de tenir 90! en mémoire :)

Dans le cas (2), google pour "l'approximation de Stirling".

Igor Krivokon
la source
3
Contre-exemple: le calcul du nombre de permutations avec N éléments nécessite une factorielle nue, et est nécessaire si vous souhaitez allouer une structure pour contenir les permutations.
Mark Jeronimus
Bon point! Ma première question était de savoir si 90! / 85! simplifié à cause d'un dénominateur commun de 5, mais en fait, c'était le dénominateur commun de 85 !. 90! / 85! = 90 * 89 * 88 * 87 * 86 * 85! / 85 !. Vous pouvez le voir plus clairement dans cette égalité.
HoldOffHunger
12

Utilisez les goyaves BigIntegerMathcomme suit:

BigInteger factorial = BigIntegerMath.factorial(n);

(Une fonctionnalité similaire pour intet longest disponible dans IntMathet LongMathrespectivement.)

dogbane
la source
6

Bien que les factorielles soient un bon exercice pour le programmeur débutant, elles ne sont pas très utiles dans la plupart des cas, et tout le monde sait comment écrire une fonction factorielle, donc elles ne sont généralement pas dans la bibliothèque moyenne.

bdonlan
la source
6
Je suis d'accord avec vous, il y a des fonctions mathématiques plus importantes. Mais à mes yeux, cette méthode devrait être standard pour que les gens puissent la réutiliser. Il n'est pas nécessaire de le mettre en œuvre plusieurs fois par plusieurs personnes. À des fins éducatives, ils peuvent le faire. Mais pour le travail quotidien, il est obsolète. C'est mon opinion. Quoi qu'il en soit, merci d'avoir répondu. Je le ferai moi-même - une autre fois.
Quel est l'avantage de la normalisation proposée? L'ajout de méthodes à la bibliothèque standard n'est pas sans frais. Comme d'autres l'ont souligné, il n'y a pas une seule meilleure solution. Lequel proposez-vous d'intégrer dans la langue? Avoir une méthode dans la bibliothèque standard ne vous fera pas gagner du temps pour comprendre votre problème, et une fois que vous avez fait cela, vous pouvez tout aussi bien sélectionner l'implémentation qui convient le mieux à la tâche.
Matt G
2
"... et tout le monde sait écrire une fonction factorielle" chaosinmotion.com/blog/?p=622
James P.
4
Être en désaccord. Les factorielles sont nécessaires pour Combinatorics , ce qui est nécessaire dans de nombreux domaines de la conception de logiciels. L'argument ne pas inclure les factorielles dans une bibliothèque mathématique intégrée est le même argument que ne pas avoir de bibliothèque mathématique intégrée.
LateralFractal
Quelle logique exceptionnelle. Absolument stellaire. Dommage que les concepteurs de la classe java.lang.Math l'ignoraient lorsqu'ils ont inclus les méthodes abs () dans cette bibliothèque.
Igor Soudakevitch le
6

je crois que ce serait le moyen le plus rapide, par une table de consultation:

private static final long[] FACTORIAL_TABLE = initFactorialTable();
private static long[] initFactorialTable() {
    final long[] factorialTable = new long[21];
    factorialTable[0] = 1;
    for (int i=1; i<factorialTable.length; i++)
        factorialTable[i] = factorialTable[i-1] * i;
    return factorialTable;
}
/**
 * Actually, even for {@code long}, it works only until 20 inclusively.
 */
public static long factorial(final int n) {
    if ((n < 0) || (n > 20))
        throw new OutOfRangeException("n", 0, 20);
    return FACTORIAL_TABLE[n];
}

Pour le type natif long(8 octets), il ne peut contenir que20!

20! = 2432902008176640000(10) = 0x 21C3 677C 82B4 0000

Évidemment, 21!provoquera un débordement.

Par conséquent, pour le type natif long, seul un maximum de 20!est autorisé, significatif et correct.

midnite
la source
1
Très bonne idée. considérant que les 20 premiers factoriels sont probablement suffisants, j'ajouterais des constantes statiques (pas besoin de les calculer à chaque lancement d'application) à la classe Math avec ces données fournies. Le fait que peu de gens aient besoin de factorielles dans leur code est une mauvaise excuse pour ne pas le supporter en cours de mathématiques.
TG
6

Étant donné que factorielle se développe si rapidement, le débordement de pile n'est pas un problème si vous utilisez la récursivité. En fait, la valeur de 20! est le plus grand que l'on puisse représenter dans un long Java. Ainsi, la méthode suivante calculera factorielle (n) ou lèvera une IllegalArgumentException si n est trop grand.

public long factorial(int n) {
    if (n > 20) throw new IllegalArgumentException(n + " is out of range");
    return (1 > n) ? 1 : n * factorial(n - 1);
}

Une autre façon (plus cool) de faire la même chose est d'utiliser la bibliothèque de flux de Java 8 comme ceci:

public long factorial(int n) {
    if (n > 20) throw new IllegalArgumentException(n + " is out of range");        
    return LongStream.rangeClosed(1, n).reduce(1, (a, b) -> a * b);
}

En savoir plus sur les factorielles utilisant les flux de Java 8

Per-Åke Minborg
la source
6

Le package Apache Commons Math a une méthode factorielle , je pense que vous pouvez l'utiliser.

Valentin Rocher
la source
Le lien est mis à jour ce
Marco Lackovic
@Krige vient de réparer le lien
fedorqui 'Alors arrête de nuire'
6

La réponse courte est: utilisez la récursivité.

Vous pouvez créer une méthode et appeler cette méthode directement dans la même méthode de manière récursive:

public class factorial {

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

    public static long calc(long n) {
        if (n <= 1)
            return 1;
        else
            return n * calc(n - 1);
    }
}
Feri
la source
5
les fonctions récursives sont bien, mais si quelqu'un essaie de compter un très gros fatiorial, il se retrouvera avec StackOverflowException;) + Je ne suis pas sûr, mais je pense que la récursivité est plus lente que la bonne vieille méthode de boucle;)
TG
comment pouvez-vous savoir qu'il se terminera par une exception stackoverflow? @TG
gumuruh
2
C'est simple. chaque récursivement met la place actuelle sur la pile afin que le programme ait la «mémoire» de l'endroit où revenir après l'appel de la méthode. La pile a ses limites. pour l'essayer par vous-même, essayez dans le code ci-dessus, changez System.out.println(calc(10));pour System.out.println(calc(Long.MAX_VALUE));vous devriez obtenir un stactrace assez long :)
TG
@TG Pour être clair, j'ai essayé ma méthode récursive qui fonctionne avec BigInteger. J'ai essayé de calculer la factorielle du nombre 8020qui m'a donné le résultat 613578884952214809325384...qui a des 27831décimales. Donc, même lorsque vous travaillez avec des nombres, cet énorme non Stackoverflowsera jeté. Bien sûr, vous avez raison, mais je doute qu'il y ait des chiffres aussi gros avec une utilisation pratique :-)
Moritz Schmidt
3

Essaye ça

public static BigInteger factorial(int value){
    if(value < 0){
        throw new IllegalArgumentException("Value must be positive");
    }

    BigInteger result = BigInteger.ONE;
    for (int i = 2; i <= value; i++) {
        result = result.multiply(BigInteger.valueOf(i));
    }

    return result;
}
Ilya Gazman
la source
3
Je crois qu'il y a un bug dans la boucle for: ça devrait l'être i <= value. La boucle for pourrait être légèrement optimisée pour (int i = 2; i <= value; i++).
Chris
2

J'ai trouvé une astuce incroyable pour trouver des factorielles dans seulement la moitié des multiplications réelles.

Veuillez être patient car il s'agit d'un article un peu long.

Pour les nombres pairs : pour réduire de moitié la multiplication avec des nombres pairs, vous vous retrouverez avec n / 2 facteurs. Le premier facteur sera le nombre dont vous prenez la factorielle, puis le suivant sera ce nombre plus ce nombre moins deux. Le numéro suivant sera le numéro précédent plus le dernier numéro ajouté moins deux. Vous avez terminé lorsque le dernier numéro que vous avez ajouté était de deux (c'est-à-dire 2) . Cela n'a probablement pas beaucoup de sens, alors laissez-moi vous donner un exemple.

8! = 8 * (8 + 6 = 14) * (14 + 4 = 18) * (18 + 2 = 20)

8! = 8 * 14 * 18 * 20 which is **40320** 

Notez que j'ai commencé par 8, puis le premier nombre que j'ai ajouté était 6, puis 4, puis 2, chaque nombre ajouté étant deux de moins que le nombre ajouté avant lui. Cette méthode équivaut à multiplier les moindres nombres avec les plus grands nombres, juste avec moins de multiplication, comme ceci:

8! = 1 * 2 * 3 * 4 * 5 * 6 * 7 * 
8! = (1 * 8) * (2 * 7) * (3 * 6) * (4 * 5)
8! = 8 * 14 * 18 * 20

Simple n'est-ce pas :)

Maintenant pour les nombres impairs: Si le nombre est impair, l'addition est la même, comme dans vous soustrayez deux à chaque fois, mais vous vous arrêtez à trois. Le nombre de facteurs change cependant. Si vous divisez le nombre par deux, vous vous retrouverez avec un nombre se terminant par 0,5. La raison en est que si nous multiplions les extrémités ensemble, il nous reste le nombre du milieu. Fondamentalement, tout cela peut être résolu en résolvant un nombre de facteurs égal au nombre divisé par deux, arrondi vers le haut. Cela n'a probablement pas beaucoup de sens non plus pour les esprits sans connaissances mathématiques, alors laissez-moi faire un exemple:

9! = 9 * (9 + 7 = 16) * (16 + 5 = 21) * (21 + 3 = 24) * (roundUp(9/2) = 5)

9! = 9 * 16 * 21 * 24 * 5 = **362880**

Remarque: Si vous n'aimez pas cette méthode, vous pouvez aussi simplement prendre la factorielle du nombre pair avant l'impair (huit dans ce cas) et la multiplier par le nombre impair (c'est-à-dire 9! = 8! * 9).

Maintenant, implémentons-le en Java:

public static int getFactorial(int num)
{
    int factorial=1;
    int diffrennceFromActualNum=0;
    int previousSum=num;

    if(num==0) //Returning  1 as factorial if number is 0 
        return 1;
    if(num%2==0)//  Checking if Number is odd or even
    { 
        while(num-diffrennceFromActualNum>=2)
        {
            if(!isFirst)
            {
                previousSum=previousSum+(num-diffrennceFromActualNum);  
            }
            isFirst=false;
            factorial*=previousSum;
            diffrennceFromActualNum+=2;
        }
    }
    else // In Odd Case (Number * getFactorial(Number-1))
    {
        factorial=num*getFactorial(num-1);
    }
    return factorial;
}

isFirstest une variable booléenne déclarée comme statique; il est utilisé pour le 1er cas où l'on ne souhaite pas modifier la somme précédente.

Essayez avec des nombres pairs et impairs.

Neeraj Jain
la source
2

Vous pouvez utiliser la récursivité.

public static int factorial(int n){    
      if (n == 0)    
        return 1;    
      else    
        return(n * factorial(n-1));    
     }

puis après avoir créé la méthode (fonction) ci-dessus:

System.out.println(factorial(number of your choice));  
    //direct example
    System.out.println(factorial(3));
Cristian Babarusi
la source
1

La seule utilisation commerciale d'une factorielle à laquelle je puisse penser est les formules Erlang B et Erlang C, et tout le monde ne travaille pas dans un centre d'appels ou pour la compagnie de téléphone. L'utilité d'une fonctionnalité pour les entreprises semble souvent dicter ce qui apparaît dans une langue - regardez toutes les fonctions de traitement des données, XML et Web dans les principales langues.

Il est facile de conserver un extrait de code factoriel ou une fonction de bibliothèque pour quelque chose comme ça.

R Ubben
la source
1

Une méthode très simple pour calculer les factorielles:

private double FACT(double n) {
    double num = n;
    double total = 1;
    if(num != 0 | num != 1){
        total = num;
    }else if(num == 1 | num == 0){
        total = 1;
    }
    double num2;
    while(num > 1){
        num2 = num - 1;
        total = total * num2;
        num = num - 1;
    }
    return total;
}

J'ai utilisé double car ils peuvent contenir des nombres massifs, mais vous pouvez utiliser tout autre type comme int, long, float, etc.

PS Ce n'est peut-être pas la meilleure solution, mais je suis nouveau dans le codage et il m'a fallu du temps pour trouver un code simple capable de calculer les factorielles, j'ai donc dû écrire la méthode moi-même, mais je mets cela ici pour aider d'autres personnes comme moi .

Kaamil Jasani
la source
1

Vous pouvez également utiliser la version récursive.

static int myFactorial(int i) {
    if(i == 1)
        return;
    else
        System.out.prinln(i * (myFactorial(--i)));
}

La récursivité est généralement moins efficace en raison de la nécessité de pousser et de pop les récursions, donc l'itération est plus rapide. D'autre part, les versions récursives utilisent moins ou pas de variables locales, ce qui est un avantage.

Hesam
la source
1

Factorielle est une fonction discrète très croissante, donc je pense que l'utilisation de BigInteger est préférable à l'utilisation de int. J'ai implémenté le code suivant pour le calcul de la factorielle d'entiers non négatifs.J'ai utilisé la récursivité au lieu d'utiliser une boucle.

public  BigInteger factorial(BigInteger x){     
    if(x.compareTo(new BigInteger("1"))==0||x.compareTo(new BigInteger("0"))==0)
        return new BigInteger("1");
    else return x.multiply(factorial(x.subtract(new BigInteger("1")))); 
}

Ici, la plage du grand entier est

-2^Integer.MAX_VALUE (exclusive) to +2^Integer.MAX_VALUE,
where Integer.MAX_VALUE=2^31.

Cependant, la plage de la méthode factorielle donnée ci-dessus peut être étendue jusqu'à deux fois en utilisant BigInteger non signé.

Sanjeet A
la source
1

Nous avons une seule ligne pour le calculer:

Long factorialNumber = LongStream.rangeClosed(2, N).reduce(1, Math::multiplyExact);
krmanish007
la source
1

Une méthode assez simple

    for ( int i = 1; i < n ; i++ )
    {
            answer = answer * i;
    }
DalekCaan99
la source
1
    /**
import java liberary class

*/
import java.util.Scanner;

/* class to find factorial of a number
*/

public class factorial
{
public static void main(String[] args)
{

// scanner method for read keayboard values

    Scanner factor= new Scanner(System.in);

    int n;
    double total = 1;
    double sum= 1;

    System.out.println("\nPlease enter an integer: ");
    n = factor.nextInt();

// evaluvate the integer is greater than zero and calculate factorial

if(n==0)

{
    System.out.println(" Factorial of 0 is 1");
}
else if (n>0)
{
    System.out.println("\nThe factorial of " + n + " is " );

    System.out.print(n);

    for(int i=1;i<n;i++)
    {
        do // do while loop for display each integer in the factorial
              {
                System.out.print("*"+(n-i) );
              }

        while ( n == 1);

      total = total * i;

    }

// calculate factorial
sum= total * n;


// display sum of factorial

    System.out.println("\n\nThe "+ n +" Factorial is : "+" "+ sum);
}

// display invalid entry, if enter a value less than zero

else

{
    System.out.println("\nInvalid entry!!");

}System.exit(0);
}
}
jith009
la source
0
public static int fact(int i){
    if(i==0)
       return 0;
    if(i>1){
       i = i * fact(--i);
    }

   return i;
}
Jaikrat
la source
1
Je pense que l'OP demande s'il y a une fonction dans l'API, pas comment en écrire une. De plus, 0! = 1 - vous souhaiterez peut-être mettre à jour votre code pour inclure ce cas.
SL Barth - Réintégrer Monica
donnera toujours 0
Tom Brito
0

Nous devons mettre en œuvre de manière itérative. Si nous implémentons récursivement, cela provoquera StackOverflow si l'entrée devient très grande (c'est-à-dire 2 milliards). Et nous devons utiliser un nombre de taille non lié tel que BigInteger pour éviter un débordement arithmatique lorsqu'un nombre factoriel devient plus grand que le nombre maximum d'un type donné (c'est-à-dire 2 milliards pour int). Vous pouvez utiliser int pour un maximum de 14 de factorielles et long pour un maximum de 20 de factorielles avant le débordement.

public BigInteger getFactorialIteratively(BigInteger input) {
    if (input.compareTo(BigInteger.ZERO) <= 0) {
        throw new IllegalArgumentException("zero or negatives are not allowed");
    }

    BigInteger result = BigInteger.ONE;
    for (BigInteger i = BigInteger.ONE; i.compareTo(input) <= 0; i = i.add(BigInteger.ONE)) {
        result = result.multiply(i);
    }
    return result;
}

Si vous ne pouvez pas utiliser BigInteger, ajoutez une vérification d'erreur.

public long getFactorialIteratively(long input) {
    if (input <= 0) {
        throw new IllegalArgumentException("zero or negatives are not allowed");
    } else if (input == 1) {
        return 1;
    }

    long prev = 1;
    long result = 0;
    for (long i = 2; i <= input; i++) {
        result = prev * i;
        if (result / prev != i) { // check if result holds the definition of factorial
            // arithmatic overflow, error out
            throw new RuntimeException("value "+i+" is too big to calculate a factorial, prev:"+prev+", current:"+result);
        }
        prev = result;
    }
    return result;
}
joohwan
la source
0
public int factorial(int num) {
        if (num == 1) return 1;
        return num * factorial(num - 1);
}
Scott Zhu
la source
Devrait utiliser long ou BigInteger;)
AxelH
0

boucle while (pour les petits nombres)

public class factorial {

public static void main(String[] args) {
    int counter=1, sum=1;

    while (counter<=10) {
        sum=sum*counter;
        counter++;
   }

    System.out.println("Factorial of 10 is " +sum);
   }
}
Dejanmarich
la source
0

Je l'ai obtenu d'EDX, utilisez-le! sa récursivité appelée

   public static int factorial(int n) {
    if (n == 1) {
        return 1;
    } else {
        return n * factorial(n-1);
    }
}
Meule
la source
0

avec récursivité:

public static int factorial(int n)
{
    if(n == 1)
    {
        return 1;
    }               
    return n * factorial(n-1);
}

avec boucle while:

public static int factorial1(int n)
{
    int fact=1;
    while(n>=1)
    {
        fact=fact*n;
        n--;
    }
    return fact;
}
Niteesh Gupta
la source
0

UTILISER LA PROGRAMMATION DYNAMIQUE EST EFFICACE

si vous voulez l'utiliser pour calculer encore et encore (comme la mise en cache)

Code Java:

int fact[]=new int[n+1]; //n is the required number you want to find factorial for.
int factorial(int num)
 {
    if(num==0){
     fact[num]=1;
     return fact[num];
       }
     else
       fact[num]=(num)*factorial(num-1);

     return fact[num];
 }
Ganesh Chowdhary Sadanala
la source
0

l'utilisation de la récursivité est la méthode la plus simple. si nous voulons trouver la factorielle de N, nous devons considérer les deux cas où N = 1 et N> 1 puisqu'en factorielle nous continuons à multiplier N, N-1, N-2 ,,,,, jusqu'à 1. si nous aller à N = 0 nous obtiendrons 0 pour la réponse. pour empêcher la factorielle d'atteindre zéro, la méthode récursive suivante est utilisée. À l'intérieur de la fonction factorielle, tandis que N> 1, la valeur de retour est multipliée par une autre initiation de la fonction factorielle. cela gardera le code appelant récursivement la factorielle () jusqu'à ce qu'il atteigne N = 1. pour le cas N = 1, il retourne N (= 1) lui-même et tout le résultat précédemment construit du retour multiplié N s est multiplié par N = 1. Ainsi donne le résultat factoriel.

static int factorial(int N) {
    if(N > 1) { 
    return n * factorial(N - 1);
    }
    // Base Case N = 1
    else { 
    return N;
    }
Vishaka Basnayake
la source