Partage
  • Partager sur Facebook
  • Partager sur Twitter

Calculer le factoriel d'un nombre à l'aide d une c

Si on entre des nombres >= 34, factoriel = 0? Pourquoi?!

    5 mars 2022 à 17:45:29

    Voici mon algorithme tout entier,

    #include <stdio.h>

    #include <stdlib.h>

    int fact =1;

    int factoriel(int n){

       If(n == 0)

          fact = 1;

       else 

          fact = n * factotiel(n - 1);

    Return fact;

    }

    int main(int argc, char* argv[]){

    int m;

    Printf("entrer le nombre dont vous voulez le factoriel");

    scanf("%d", m);

    printf("le factoriel de %d est %d", m, factoriel(m));

    return 0;

    }

    Mon probleme est que quand j entre des nombres à partir de 34 en montant on m affiche un factoriel egal à 0... pourquoi?

    J ai pensé à un dépassement de capacité 

    Si c est le cas alors comment je peux faire pour avoir le resultat que je souhaiterais avoir (le factoriel de n importe quel nombre entré)

    Merci de votre éclairage 🙏

    • Partager sur Facebook
    • Partager sur Twitter
      5 mars 2022 à 17:47:38

      Utilises le bouton code </> du forum pour poster ton code ! (tu peux modifier ton post, lien modifier en haut à droite du post).
      • Partager sur Facebook
      • Partager sur Twitter
      ...
        5 mars 2022 à 18:01:23

        Est-ce que tu as besoin de calculer les factorielles parce que c'est un calcul intermédiaire (par exemple pour calculer des coefficients binomiaux ou des coefficients de développements en série), ou bien tu as juste besoin de calculer les factorielles pour elles-mêmes ?

        Dans le premier cas, il faut procéder autrement et ne surtout pas passer par les factorielles.

        Dans le second cas, tu peux utiliser des 'double' au lieu de 'int' : ça donnera une valeur approchée qui, peut-être, te satisfera ?

        -
        Edité par robun 5 mars 2022 à 18:02:34

        • Partager sur Facebook
        • Partager sur Twitter
          5 mars 2022 à 18:35:15

          Je suis même surpris que tu te rendes jusqu'à 34. Mon code déconne à partir de 17.
          Avec des long long, je me rend jusqu'à 20.
          Comme l'a dit robun, ce serait mieux avec les doubles.

          Ou bien passe en Python. Avec 34!

          295232799039604140847618609643520000000

          -
          Edité par PierrotLeFou 5 mars 2022 à 18:39:01

          • Partager sur Facebook
          • Partager sur Twitter

          Le Tout est souvent plus grand que la somme de ses parties.

            5 mars 2022 à 19:51:03

            @marsalla, ta ligne :
            int fact =1;
            Doit être impérativement déplacée à l'intérieur de ta fonction. Actuellement ta fonction ne donne le bon résultat que la première fois où elle est appelée.
            Et calculer la factorielle de 17, c'est déjà un beau nombre!
            • Partager sur Facebook
            • Partager sur Twitter

            En recherche d'emploi.

              5 mars 2022 à 21:04:28

              Hello,

              comme log₂(12!)≈28.8<31<32<log₂(13!)<log₂(20!)≈61.1<63<log₂(21!)≈65.5<log₂(33!)≈122.7<127<log₂(34!)≈127.8<128<log₂(35!)≈132.9 :

              • un entier 32 bits (signé ou non) permet de stocker au moins 12! ;
              • un entier 64 bits (signé ou non) permet de stocker au moins 20! ;
              • en complément à 2, un entier signé de 128 bits permet de stocker au moins 33!;
              • en complément à 2, un entier non signé de 128 bits permet de stocker au moins 34!.

              Donc soit ça déconne avant 17 (à 13) ou après (à 21) mais pas à 17 ... ou alors il y a un autre soucis (ou une plateforme exotique avec un entier sur 48 bits ⁈ ou aut'chose encore).

              Un bug à 34 signifierait l'utilisation d'un entier non signé sur 128 bits (disponible en extension GNU par exemple) ou d'une plateforme où int fait 128 bits … 

              Sinon pour des entiers plus longs il faut utiliser … un implémentation d'entiers longs à précision arbitraire (ou une bibliothèque tierce ou une implémentation perso). Là la limite est celles des ressources à disposition. Mais bon, si tu fais un exo sur les factorielles ce ne sera pas à ta portée.

              • Partager sur Facebook
              • Partager sur Twitter
                6 mars 2022 à 11:35:17

                PierrotLeFou a écrit:

                Je suis même surpris que tu te rendes jusqu'à 34...

                Ou bien passe en Python. Avec 34!

                En C avec gmp :

                #include <gmp.h>
                
                int main (void)
                {
                    mpz_t result;
                    mpz_init(result);
                    mpz_set_ui(result, 1);
                
                    mpz_t k;
                    mpz_init(k);
                
                    for (int i=1; i<= 56; i++)
                    {
                        mpz_set_ui(k, i);
                        mpz_mul (result, result, k);
                        gmp_printf ("%2d : %Zd\n", i,  result);
                    }
                
                    return 0;
                }
                
                 1 : 1
                 2 : 2
                 3 : 6
                 4 : 24
                 5 : 120
                 6 : 720
                 7 : 5040
                 8 : 40320
                 9 : 362880
                10 : 3628800
                11 : 39916800
                12 : 479001600
                13 : 6227020800
                14 : 87178291200
                15 : 1307674368000
                16 : 20922789888000
                17 : 355687428096000
                18 : 6402373705728000
                19 : 121645100408832000
                20 : 2432902008176640000
                21 : 51090942171709440000
                22 : 1124000727777607680000
                23 : 25852016738884976640000
                24 : 620448401733239439360000
                25 : 15511210043330985984000000
                26 : 403291461126605635584000000
                27 : 10888869450418352160768000000
                28 : 304888344611713860501504000000
                29 : 8841761993739701954543616000000
                30 : 265252859812191058636308480000000
                31 : 8222838654177922817725562880000000
                32 : 263130836933693530167218012160000000
                33 : 8683317618811886495518194401280000000
                34 : 295232799039604140847618609643520000000
                35 : 10333147966386144929666651337523200000000
                36 : 371993326789901217467999448150835200000000
                37 : 13763753091226345046315979581580902400000000
                38 : 523022617466601111760007224100074291200000000
                39 : 20397882081197443358640281739902897356800000000
                40 : 815915283247897734345611269596115894272000000000
                41 : 33452526613163807108170062053440751665152000000000
                42 : 1405006117752879898543142606244511569936384000000000
                43 : 60415263063373835637355132068513997507264512000000000
                44 : 2658271574788448768043625811014615890319638528000000000
                45 : 119622220865480194561963161495657715064383733760000000000
                46 : 5502622159812088949850305428800254892961651752960000000000
                47 : 258623241511168180642964355153611979969197632389120000000000
                48 : 12413915592536072670862289047373375038521486354677760000000000
                49 : 608281864034267560872252163321295376887552831379210240000000000
                50 : 30414093201713378043612608166064768844377641568960512000000000000
                51 : 1551118753287382280224243016469303211063259720016986112000000000000
                52 : 80658175170943878571660636856403766975289505440883277824000000000000
                53 : 4274883284060025564298013753389399649690343788366813724672000000000000
                54 : 230843697339241380472092742683027581083278564571807941132288000000000000
                55 : 12696403353658275925965100847566516959580321051449436762275840000000000000
                56 : 710998587804863451854045647463724949736497978881168458687447040000000000000

                -
                Edité par rouIoude 6 mars 2022 à 20:34:30

                • Partager sur Facebook
                • Partager sur Twitter
                ...
                  7 mars 2022 à 20:15:45

                  Dans factorielle 34, il y a le produit de 17 nombres pairs, dont 8 multiples de 4, 4 multiples de 8, 2 multiples de 16 et 1 de 32.

                  Ce qui fait que 34! est divisible par 2^(17+8+4+2+1) = 2^32 (edit)

                  A mon avis, ça a quelque chose à voir avec le codage sur 32 bits des entiers signés complément à 2.

                  En fait, ça déconne avant

                  #include <stdio.h>
                  
                  int main() {
                  	int f = 1;
                  	for (int i = 1; i <= 35; i++) {
                  		f *= i;
                  		printf("%2d %d\n", i, f);
                  	}
                  	return 0;
                  }
                  
                   1 1
                   2 2
                   3 6
                   4 24
                   5 120
                   6 720
                   7 5040
                   8 40320
                   9 362880
                  10 3628800
                  11 39916800
                  12 479001600
                  13 1932053504
                  14 1278945280          # hum hum
                  15 2004310016
                  16 2004189184
                  17 -288522240          # houla
                  18 -898433024
                  19 109641728
                  20 -2102132736
                  21 -1195114496
                  22 -522715136
                  23 862453760
                  24 -775946240
                  25 2076180480
                  26 -1853882368
                  27 1484783616
                  28 -1375731712
                  29 -1241513984
                  30 1409286144
                  31 738197504
                  32 -2147483648
                  33 -2147483648
                  34 0                # doh!
                  35 0
                  




                  -
                  Edité par michelbillaud 8 mars 2022 à 8:49:13

                  • Partager sur Facebook
                  • Partager sur Twitter
                    7 mars 2022 à 21:01:25

                    Ton hum hum est une ligne trop loin …
                    • Partager sur Facebook
                    • Partager sur Twitter
                      7 mars 2022 à 23:20:35

                      Exact : 13! ne peut pas finir par le chiffre 4 puisqu'il est divisible par 100 (au moins − il contient 2, 5, 10).

                      -
                      Edité par robun 7 mars 2022 à 23:20:48

                      • Partager sur Facebook
                      • Partager sur Twitter
                        7 mars 2022 à 23:43:17

                        Comme on dévie déjà pas mal du sujet initial, je vais me permettre une petite vanne (à la putaclick) …

                        «Vous ne le croirez jamais, mais le nombre de minutes dans 2 heures est 5 !
                        pire encore ! le nombre d'heures dans une journée est 4 !»

                         :p

                        • Partager sur Facebook
                        • Partager sur Twitter
                          8 mars 2022 à 1:58:08

                          existe-t-il une fonction "pseudo" factorielle qui serait le produit des N premiers "nombres premiers",
                          ou des nombres premiers <= N?
                          Encore faut-il avoir cette liste de nombres premiers.
                          • Partager sur Facebook
                          • Partager sur Twitter

                          Le Tout est souvent plus grand que la somme de ses parties.

                            8 mars 2022 à 8:53:13

                            White Crow a écrit:

                            Ton hum hum est une ligne trop loin …


                            Certainement, mais au rang 14 on voit, sans faire aucun calcul, et sans rien supposer sur le nombre de bits des entiers, que le résultat ne s'est pas allongé alors qu'on a multiplié par un nombre supérieur à 10.

                            C'est suffisant pour tirer le signal d'alarme sur l'invraisemblance du résultat.

                            Comme le signe moins pour 17,  bien sur. Mais 14 c'est avant 17 :-)

                            Ps m'étais planté dans les additions dans le message d'avant.  34!  est bien divisible par 2^32

                            (17 + 8 + 4 + 2 + 1 = 32, pas 30...)

                            -
                            Edité par michelbillaud 8 mars 2022 à 9:01:01

                            • Partager sur Facebook
                            • Partager sur Twitter
                              8 mars 2022 à 9:00:22

                              michelbillaud a écrit:

                              White Crow a écrit:

                              Ton hum hum est une ligne trop loin …


                              Certainement, mais au rang 14 on voit, sans faire aucun calcul, et sans rien supposer sur le nombre de bits des entiers, que le résultat ne s'est pas allongé alors qu'on a multiplié par un nombre supérieur à 10. C'est suffisant pour tirer le signal d'alarme.

                              Comme le signe moins pour 17.

                              Ps m'étais planté dans les additions dans le message d'avant.  34!  est bien divisible par 2^32

                              -
                              Edité par michelbillaud il y a moins de 30s


                               

                              robun a écrit:

                              Exact : 13! ne peut pas finir par le chiffre 4 puisqu'il est divisible par 100 (au moins − il contient 2, 5, 10).

                              -
                              Edité par robun il y a environ 9 heures


                              Si un nombre se termine par 0 si on le multiplie par un autre nombre, le résultat se terminera par 0.

                              PierrotLeFou a écrit:

                              existe-t-il une fonction "pseudo" factorielle qui serait le produit des N premiers "nombres premiers",
                              ou des nombres premiers <= N?
                              Encore faut-il avoir cette liste de nombres premiers.

                              Oui, il s'agit de la primorielle.

                              • Partager sur Facebook
                              • Partager sur Twitter
                                8 mars 2022 à 10:39:53

                                Pendant que je faisais mes courses (du pain et du produit pour déboucher #mylife :-)) j'ai un peu généralisé le truc précédent, à savoir que   34! est divisible par 2^32. Et donc ça fait 0 si on calcule sur des entiers 32 bits.

                                Pour 64 bits ça sera vrai pour 66!,  pour 128 bits pour 130!, pour 256bits 258! etc. 

                                Bref pour 2^n bits, c'est vrai pour  (2^n + 2)!

                                Idée de la preuve : dans les entiers de 1 à 2^n, il y en a 2^(n -1= qui sont multiples de 2,  parmi eux 2^(n -2) qui sont multiples de 4, parmi eux 2^(n-3) multiples de 8, etc.



                                Donc, dans 2^n ! le facteur 2 apparait à la puissance 1 + 2 + 4 + ... 2^(n-1) =    2^n - 1

                                Pour avoir la puissance 2^n, il nous faut la factorielle du nombre pair qui suit 2^n, et c'est 2^n + 2.

                                En remplaçant int par long dans le prog précédent

                                33 1585267068834414592
                                64 -9223372036854775808
                                65 -9223372036854775808
                                66 0
                                67 0
                                
                                l'expérience corrobore la théorie. C'est-y pas beau la science ?

                                -
                                Edité par michelbillaud 8 mars 2022 à 10:45:17

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  8 mars 2022 à 10:40:09

                                  J'ajoute ma petite pierre à l'édifice !

                                  Pour ma part, quand j'ai besoin de factorielles, sachant qu'au delà de 13 à explose les int32, je fais un tableau statique avec les valeurs précalculées. Du coup ça va vite, en O(1).

                                  Evidemment, pour la question initiale, c'est l'exercice classique pour s'entraîner à la récursivité, on l'a tous fait. Il ne faut pas aller au delà de 13 tout simplement.

                                  Après, dans les faits, on a rarement besoin de factorielles qui montent aussi haut.

                                  Bien sur on va me dire que pour toute de qui est combinatoire, on peut en avoir besoin, car on a des X!/(X-N)!  mais il y a des optimisations possibles pour trouver le résultat. 

                                  Un peu comme quand les matheux font (-1)^N, c'est  mathématiquement élégant, mais il ne faut pas faire ça en informatique. 

                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                    8 mars 2022 à 12:40:47

                                    Tout à fait : il y a d'un côté l'écriture mathématique, utile pour la théorie, et de l'autre les calculs de l'ordinateur, qui n'utilisent surtout pas l'écriture mathématique.

                                    Par exemple pour calculer cos(x), on pourrait croire qu'il faut calculer :

                                    \( 1 - \dfrac{x^2}{2!} + \dfrac{x^4}{4!} + \cdots + (-1)^n\dfrac{x^{2n}}{(2n)!} + \cdots \)

                                    et donc calculer des factorielles. Surtout pas ! Et ce n'est pas une question d'optimisation : calculer 2!, puis 4!, puis 6! et ainsi de suite, c'est refaire sans cesse les mêmes calculs (c'est de l'optimisation à l'envers : comment faire le pire...)

                                    Ce qu'il faut faire, c'est définir une suite \( u_n \) telle que la somme à calculer est :

                                    \( 1 + u_1(x) + u_2(x) + \cdots + u_n(x) + \cdots \)

                                    Une suite se calcule de deux façons :

                                    • soit avec une formule immédiate, ici : \( u_n(x) = (-1)^n\dfrac{x^{2n}}{(2n)!} \)
                                    • soit par récurrence, ici : (pour n >= 1) \( u_n(x) =  - \, \dfrac{x^2}{2n(2n-1)} \cdot u_{n-1}(x) \) (on initialise à u_0(x) = 1 et on a calculé une fois pour toutes \( x^2 \)).

                                    Pour les calculs pratiques, c'est bien sûr la deuxième méthode qu'il faut employer ! La boucle principale pourrait ressembler à :

                                    deux_n         += 2 ;
                                    deux_n_moins_1 += 2 ;
                                    u *= -x_carre / (deux_n * deux_n_moins_1) ;
                                    somme += u ;

                                    (J'ai écrit différemment le calcul de 2n(2n-1), là encore l'écriture mathématique n'est pas bien adaptée.)

                                    Il faudra pas mal de termes pour avoir un dépassement de capacité : chaque u est de plus en plus petit, et diviser par 2n(2n-1) peut se faire avec des 'double' tant que n ne vaut pas dans les 10^je-ne-sais-pas-combien...

                                    -
                                    Edité par robun 8 mars 2022 à 12:44:04

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      8 mars 2022 à 12:53:23

                                      robun a écrit:

                                      Par exemple pour calculer cos(x), on pourrait croire qu'il faut calculer :

                                      \( 1 - \dfrac{x^2}{2!} + \dfrac{x^4}{4!} + \cdots + (-1)^n\dfrac{x^{2n}}{(2n)!} + \cdots \)

                                      et donc calculer des factorielles. Surtout pas !

                                      En fait il faut regarder les éléments qui se calculent de proche en proche

                                      • le coefficient qui augmente de 2
                                      • la puissance de x qui est multipliée par x au carré
                                      • la factorielle qui est multipliée par le coefficient et le coeff + 1
                                      • le signe qui alterne
                                      et tout ca dans une somme qui augmente du signe multiplié par la puissance divisée par la factorielle.

                                      -
                                      Edité par michelbillaud 8 mars 2022 à 12:54:20

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        8 mars 2022 à 17:57:14

                                        Et le cos() ne se calcule pas avec des int mais des doubles.
                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        Le Tout est souvent plus grand que la somme de ses parties.

                                          8 mars 2022 à 19:08:54

                                          PierrotLeFou a écrit:

                                          Et le cos() ne se calcule pas avec des int mais des doubles.

                                          Disons que cela amène dans l'algo de @robun, à choisir si deux_n et deux_n_moins_un sont des int ou des double. Dans le premier cas on aura plus de calculs entiers, mais on se prend un conversion couteuse de int vers double dans la boucle, dans le second cas tout est double et c'est peut-être plus optimal.

                                          • Partager sur Facebook
                                          • Partager sur Twitter

                                          En recherche d'emploi.

                                          Calculer le factoriel d'un nombre à l'aide d une c

                                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                          • Editeur
                                          • Markdown