Comment trouver la factorielle d'un nombre positif?

18

Le défi:

Écrivez un programme ou une fonction qui entre un nombre positif et renvoie sa factorielle .

Remarque: Il s'agit d'une question de . Veuillez ne pas prendre la question et / ou les réponses au sérieux. Plus d'informations ici . Chaque question de est également une question de , donc la réponse la plus votée gagne.

alephalpha
la source
6
Voir aussi L'évolution du programmeur Haskell .
Petr Pudlák
4
-1, désolé, car nous recevons un énorme flot de ces questions de contrôle de code et cela n'ajoute vraiment rien de nouveau pour elles
Poignée de porte
Le code-trolling est en cours de suppression, conformément à la position officielle. Cette question a un bon nombre de votes avec de nombreuses réponses, dont beaucoup sont extrêmement votées. Il a reçu un peu plus de 50% de votes "supprimer" sur le sondage , mais il est unique en ce qu'il a reçu tant de réponses et de votes, donc je le bloque pour une signification historique.
Poignée de porte

Réponses:

46

Il s'agit d'un problème de calcul numérique très simple que nous pouvons résoudre avec l'approximation de Stirling :

Formule d'approximation de Stirling

Comme vous pouvez le voir, cette formule comporte une racine carrée, dont nous aurons également besoin d'un moyen d'approximation. Nous choisirons la soi-disant "méthode babylonienne" pour cela car c'est sans doute la plus simple:

Méthode babylonienne

Notez que le calcul de la racine carrée de cette façon est un bon exemple de récursivité.

Tout rassembler dans un programme Python nous donne la solution suivante à votre problème:

def sqrt(x, n): # not the same n as below
    return .5 * (sqrt(x, n - 1) + x / sqrt(x, n - 1)) if n > 0 else x

n = float(raw_input())
print (n / 2.718) ** n * sqrt(2 * 3.141 * n, 10)

Avec une simple modification, le programme ci-dessus peut produire une table soignée de factorielles:

1! =    0.92215
2! =    1.91922
3! =    5.83747
4! =   23.51371
5! =  118.06923
6! =  710.45304
7! = 4983.54173
8! = 39931.74015
9! = 359838.58817

Cette méthode doit être suffisamment précise pour la plupart des applications.

nwk
la source
16
+1 La simplicité et la précision de cette méthode en font un gagnant incontournable
Joe the Person
44

C #

Désolé, mais je déteste la fonction récursive.

public string Factorial(uint n) {
    return n + "!";
}
tia
la source
1
Techniquement, vous avez satisfait le brief! ;) +1 pour bref abus
WallyWest
36

Java

public int factorial ( int n ) {
switch(n){
case 0: return 1;
case 1: return 1;
case 2: return 2;
case 3: return 6;
case 4: return 24;
case 5: return 120;
case 6: return 720;
case 7: return 5040;
case 8: return 40320;
case 9: return 362880;
case 10: return 3628800;
case 11: return 39916800;
case 12: return 479001600;
default : throw new IllegalArgumentException();
}
}
Emory
la source
16
Je l'ai essayé - très efficace. Livré avec la prochaine version. :)
Johannes
Outre le "syndrome de nombres magiques", cela pourrait en fait être une bonne implémentation tant que n <13, et encore moins de piles. Écrivez-le "cas 4: retournez 4 * 3 * 2;" et vous auriez une classe décente, beaucoup plus rapide que l'ancienne récursive.
Fabinout
6
@Fabinout, l'implémentation est correcte même pour n> = 13. 13!> Entier.MAX_VALUE.
emory
21

Python

Bien sûr, la meilleure façon de résoudre tout problème est d'utiliser des expressions régulières:

import re

# adapted from http://stackoverflow.com/q/15175142/1333025
def multiple_replace(dict, text):
  # Create a regular expression  from the dictionary keys
  regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
  # Repeat while any replacements are made.
  count = -1
  while count != 0:
    # For each match, look-up corresponding value in dictionary.
    (text, count) = regex.subn(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
  return text

fdict = {
    'A': '@',
    'B': 'AA',
    'C': 'BBB',
    'D': 'CCCC',
    'E': 'DDDDD',
    'F': 'EEEEEE',
    'G': 'FFFFFFF',
    'H': 'GGGGGGGG',
    'I': 'HHHHHHHHH',
    'J': 'IIIIIIIIII',
    'K': 'JJJJJJJJJJJ',
    'L': 'KKKKKKKKKKKK',
    'M': 'LLLLLLLLLLLLL',
    'N': 'MMMMMMMMMMMMMM',
    'O': 'NNNNNNNNNNNNNNN',
    'P': 'OOOOOOOOOOOOOOOO',
    'Q': 'PPPPPPPPPPPPPPPPP',
    'R': 'QQQQQQQQQQQQQQQQQQ',
    'S': 'RRRRRRRRRRRRRRRRRRR',
    'T': 'SSSSSSSSSSSSSSSSSSSS',
    'U': 'TTTTTTTTTTTTTTTTTTTTT',
    'V': 'UUUUUUUUUUUUUUUUUUUUUU',
    'W': 'VVVVVVVVVVVVVVVVVVVVVVV',
    'X': 'WWWWWWWWWWWWWWWWWWWWWWWW',
    'Y': 'XXXXXXXXXXXXXXXXXXXXXXXXX',
    'Z': 'YYYYYYYYYYYYYYYYYYYYYYYYYY'}

def fact(n):
    return len(multiple_replace(fdict, chr(64 + n)))

if __name__ == "__main__":
    print fact(7)
Petr Pudlák
la source
1
Bien sûr en effet :)
Pierre Arlaud
15

Haskell

Le code court est un code efficace, alors essayez ceci.

fac = length . permutations . flip take [1..]

Pourquoi c'est à la traîne:

Je ris de tout codeur qui a écrit ça ... L'inefficacité est magnifique. Également probablement incompréhensible pour tout programmeur Haskell qui ne peut pas réellement écrire une fonction factorielle.

Edit: J'ai posté cela il y a un moment maintenant, mais je pensais clarifier pour les futures personnes et les personnes qui ne peuvent pas lire Haskell.

Le code ici prend la liste des nombres 1 à n, crée la liste de toutes les permutations de cette liste et renvoie la longueur de cette liste. Sur ma machine, cela prend environ 20 minutes pour 13!. Et puis cela devrait prendre quatre heures pour 14! puis deux jours et demi pour 15!. Sauf qu'à un moment donné, vous manquez de mémoire.

Edit 2: En fait, vous ne manquerez probablement pas de mémoire car il s'agit de Haskell (voir le commentaire ci-dessous). Vous pourriez être en mesure de le forcer à évaluer la liste et à la garder en mémoire d'une manière ou d'une autre, mais je ne connais pas suffisamment l'optimisation (et l'optimisation) de Haskell pour savoir exactement comment faire cela.

jgon
la source
Hideux et pourtant si élégant, tout en même temps.
PLL
1
Êtes-vous sûr du problème de mémoire? À tout moment, vous devez conserver en mémoire: - la liste [1..n]. - Une permutation particulière de [1..n], consignée à un thunk pour le reste des permutations (polynôme en n). - Un accumulateur pour la lengthfonction.
John Dvorak
Bon point, probablement pas vraiment. Je n'y ai pas trop réfléchi. J'ajouterai un commentaire en bas.
jgon
10

C #

Comme il s'agit d'un problème mathématique, il est logique d'utiliser une application spécialement conçue pour résoudre les problèmes mathématiques pour effectuer ce calcul ...

Étape 1:

Installez MATLAB. Un essai fonctionnera, je pense, mais ce problème super compliqué est probablement suffisamment important pour mériter l'achat de la version complète de l'application.

Étape 2:

Incluez le composant MATLAB COM dans votre application.

Étape 3:

public string Factorial(uint n) {
    MLApp.MLApp matlab = new MLApp.MLApp();
    return matlab.Execute(String.Format("factorial({0})", n);
}
Moshe Katz
la source
Matlab pour les étudiants commence à 100 $. Les versions professionnelles ou les licences de site peuvent atteindre des milliers.
Moshe Katz
4
Moshe Katz - justifié à cause des factorielles.
Mike H.
9

C #

Les factorielles sont une opération mathématique de niveau supérieur qui peut être difficile à digérer d'un seul coup. La meilleure solution dans des problèmes de programmation comme celui-ci est de décomposer une tâche importante en tâches plus petites.

Maintenant, n! est défini comme 1 * 2 * ... * n, donc, essentiellement une multiplication répétée, et la multiplication n'est rien d'autre que l'addition répétée. Donc, avec cela à l'esprit, ce qui suit résout ce problème:

long Factorial(int n)
{
    if(n==0)
    {
        return 1;
    }

    Stack<long> s = new Stack<long>();
    for(var i=1;i<=n;i++)
    {
        s.Push(i);
    }
    var items = new List<long>();
    var n2 = s.Pop();
    while(s.Count >0)
    {
        var n3 = s.Pop();
        items.AddRange(FactorialPart(n2,n3));
        n2 = items.Sum();
    }
    return items.Sum()/(n-1);
}

IEnumerable<long> FactorialPart(long n1, long n2)
{
    for(var i=0;i<n2;i++){
        yield return n1;
    }
}
Matt Sieker
la source
Vous avez un goulot d'étranglement envoyant tout cela via un processeur ou un cœur, que je pense avoir résolu dans ma réponse :-)
Paul
9
#include <math.h>

int factorial(int n)
{
    const double g = 7;
    static const double p[] = { 0.99999999999980993, 676.5203681218851,
                                -1259.1392167224028, 771.32342877765313,
                                -176.61502916214059, 12.507343278686905,
                                -0.13857109526572012, 9.9843695780195716e-6,
                                1.5056327351493116e-7 };
    double z = n - 1 + 1;
    double x = p[0];
    int i;
    for ( i = 1; i < sizeof(p)/sizeof(p[0]); ++i )
        x += p[i] / (z + i);
    return sqrt(2 * M_PI) * pow(z + g + 0.5, z + 0.5)  * exp(-z -g -0.5) * x + 0.5;
}

Trolls:

  • Une méthode 100% correcte de calcul factoriel qui rate complètement le point de le faire de manière itérative ou récursive.
  • Vous ne savez pas pourquoi cela fonctionne et ne pouvez pas le généraliser pour faire autre chose.
  • Plus coûteux que de simplement le calculer avec des mathématiques entières.
  • Le code ( z = n - 1 + 1) sous-optimal le plus évident ( ) est en fait auto-documenté si vous savez ce qui se passe.
  • Pour plus de pêche à la traîne, je devrais calculer en p[]utilisant un calcul récursif des coefficients de série!

(C'est l' approximation de Lanczos de la fonction gamma )

Ben Jackson
la source
Y a-t-il un point - 1 + 1ici? Mon compilateur l'optimise (ce n'est pas un nombre à virgule flottante où l'optimisation de code comme celui-ci pourrait être dangereux), il semble donc inutile.
Konrad Borowski
4
@xfix: double z = n - 1fait partie de l'approximation de la fonction gamma. Le + 1est de la relation que gamma(n + 1) = n!pour l'entier n.
Ben Jackson
9

Nous savons tous de l'université que la façon la plus efficace de calculer une multiplication est d'utiliser des logarithmes. Après tout, pourquoi les gens utiliseraient-ils des tables de logarithmes pendant des centaines d'années?

Donc, à partir de l'identité, a*b=e^(log(a)+log(b))nous formons le code Python suivant:

from math import log,exp

def fac_you(x):
    return round(exp(sum(map(log,range(1,x+1)))))

for i in range(1,99):
    print i,":",fac_you(i)

Il crée une liste de nombres de 1à x, (le +1est nécessaire parce que Python aspire) calcule le logarithme de chacun, additionne les nombres, élève le e à la puissance de la somme et arrondit finalement la valeur à l'entier le plus proche (parce que Python aspire) . Python a une fonction intégrée pour calculer les factorielles, mais il ne fonctionne que pour les entiers, donc il ne peut pas produire de grands nombres (parce que Python craint). C'est pourquoi la fonction ci-dessus est nécessaire.

Btw, un conseil général pour les étudiants est que si quelque chose ne fonctionne pas comme prévu, c'est probablement parce que la langue est nulle.

nitro2k01
la source
J'aimerais pouvoir donner quelques votes supplémentaires pour la description, mais Python craint
Mark K Cowan
1
J'ai ri de "fac you"
Number9
8

Malheureusement, Javascript n'a pas de méthode intégrée pour calculer la factorielle. Mais, vous pouvez utiliser sa signification en combinatoire pour déterminer la valeur néanmoins:

La factorielle d'un nombre n est le nombre de permutations d'une liste de cette taille.

Ainsi, nous pouvons générer chaque liste de nombres à n chiffres, vérifier s'il s'agit d'une permutation, et si oui, incrémenter un compteur:

window.factorial = function($nb_number) {
  $nb_trials = 1
  for($i = 0; $i < $nb_number; $i++) $nb_trials *= $nb_number
  $nb_successes = 0
  __trying__:
  for($nb_trial = 0; $nb_trial < $nb_trials; $nb_trial++){
    $a_trial_split = new Array
    $nb_tmp = $nb_trial
    for ($nb_digit = 0; $nb_digit < $nb_number; $nb_digit++){
      $a_trial_split[$nb_digit] = $nb_tmp - $nb_number * Math.floor($nb_tmp / $nb_number)
      $nb_tmp = Math.floor($nb_tmp / $nb_number)
    }
    for($i = 0; $i < $nb_number; $i++)
      for($j = 0; $j < $nb_number; $j++)
        if($i != $j)
          if($a_trial_split[$i] == $a_trial_split[$j])
            continue __trying__
    $nb_successes += 1
  }
  return $nb_successes
}

alert("input a number")
document.open()
document.write("<input type = text onblur = alert(factorial(parseInt(this.value))))>")
document.close()


Trolls:

  • Types de notation hongroise, snake_case et sigils inutiles . Comment est-ce mal?
  • J'ai inventé ma propre convention pour les étiquettes de saut, incompatible avec l'utilisation actuelle de cette convention.
  • Chaque variable possible est accidentellement globale.
  • La solution n'est pas O(n), non O(n!), mais O(n^n). Cela seul aurait suffi pour se qualifier ici.
  • Incrémenter un nombre puis convertir en base-n est une mauvaise façon de générer une liste de séquences. Même si nous voulions des doublons. Une rupture mystérieuse pour n> 13 n'est pas la seule raison.
  • Bien sûr, nous aurions pu utiliser number.toString(base), mais cela ne fonctionne pas pour les bases supérieures à 36. Oui, je sais 36! c'est beaucoup , mais quand même ...
  • Ai-je mentionné que Javascript avait l'opérateur de module? OuMath.pow ? Non? Tant pis.
  • Refuser d'utiliser en ++dehors de for-loops le rend encore plus mystérieux. Aussi, ==c'est mauvais.
  • Constructions en boucle sans renfort profondément imbriquées. En outre, les conditions imbriquées au lieu de ET. De plus, la condition extérieure aurait pu être évitée en terminant la boucle intérieure à $i.
  • Les fonctions new Array, document.write(avec des amis) et alert(au lieu d'une invite ou d'une étiquette d'entrée) forment un trifecta complet de péchés de choix de fonction. Pourquoi l'entrée est-elle ajoutée dynamiquement après tout?
  • Gestionnaires d'événements en ligne. Oh, et la tuyauterie profonde est un enfer à déboguer.
  • Les attributs non cotés sont amusants et les espaces autour les =rendent encore plus difficiles à lire.
  • Ai-je déjà mentionné que je déteste les points-virgules?
John Dvorak
la source
8

Ruby et WolframAlpha

Cette solution utilise l'API REST WolframAlpha pour calculer la factorielle, avec RestClient pour récupérer la solution et Nokogiri pour l'analyser. Il ne réinvente aucune roue et utilise des technologies bien testées et populaires pour obtenir le résultat de la manière la plus moderne possible.

require 'rest-client'
require 'nokogiri'

n = gets.chomp.to_i
response = Nokogiri::XML(RestClient.get("http://api.wolframalpha.com/v2/query?input=#{n}!&format=moutput&appid=YOUR_APP_KEY"))
puts response.xpath("//*/moutput/text()").text
migimunz
la source
7

Javascript

Javascript est un langage de programmation fonctionnel, cela signifie que vous devez utiliser des fonctions pour tout car c'est plus rapide.

function fac(n){
    var r = 1,
        a = Array.apply(null, Array(n)).map(Number.call, Number).map(function(n){r = r * (n + 1);});
    return r;
}
Luka
la source
1
Peux-tu expliquer?
Mhmd
7
1 n'est pas une fonction. Votre code est donc lent.
Pierre Arlaud
4
@ArlaudPierre r = -~(function(){})résoudra sûrement cela.
nitro2k01
4
Je suis sur une machine de travail donc je ne veux pas vraiment installer cette langue. Où puis-je trouver une version qui fonctionnera dans mon navigateur?
joeytwiddle
3
J'ai un peu peur d'utiliser Google parce que mon patron a un compte avec eux, et je ne veux pas qu'il sache que je joue au golf au travail. Je cherchais une extension pour Firefox qui pourrait exécuter Javascript, mais je n'arrive pas à en trouver une. Certains de mes amis utilisent Javascript sur jsfiddle.net mais cela utilise l'électricité de quelqu'un d'autre, ce qui est un peu comme voler. Ma mère a dit que je ne devrais pas traîner avec des gens comme ça, mais ce sont mes amis alors que puis-je faire? Quoi qu'il en soit, elle prend parfois plus de crème que nécessaire. Merci pour les conseils, j'utilise Ctrl-Shift-J ou K dans Firefox. Clause de non-responsabilité: # comment-trolling
joeytwiddle
5

Utilisation de Bogo-Sort en Java

public class Factorial {
    public static void main(String[] args) {
        //take the factorial of the integers from 0 to 7:
        for(int i = 0; i < 8; i++) {
            System.out.println(i + ": " + accurate_factorial(i));
        }
    }

    //takes the average over many tries
    public static long accurate_factorial(int n) {
        double sum = 0;
        for(int i = 0; i < 10000; i++) {
            sum += factorial(n);
        }
        return Math.round(sum / 10000);
    }

    public static long factorial(int n) {
        //n! = number of ways to sort n
        //bogo-sort has O(n!) time, a good approximation for n!
        //for best results, average over several passes

        //create the list {1, 2, ..., n}
        int[] list = new int[n];
        for(int i = 0; i < n; i++)
            list[i] = i;

        //mess up list once before we begin
        randomize(list);

        long guesses = 1;

        while(!isSorted(list)) {
            randomize(list);
            guesses++;
        }

        return guesses;
    }

    public static void randomize(int[] list) {
        for(int i = 0; i < list.length; i++) {
            int j = (int) (Math.random() * list.length);

            //super-efficient way of swapping 2 elements without temp variables
            if(i != j) {
                list[i] ^= list[j];
                list[j] ^= list[i];
                list[i] ^= list[j];
            }
        }
    }

    public static boolean isSorted(int[] list) {
        for(int i = 1; i < list.length; i++) {
            if(list[i - 1] > list[i])
                return false;
        }
        return true;
    }
}

Cela fonctionne en fait, très lentement, et ce n'est pas exact pour des nombres plus élevés.

James Hagborg
la source
4

PERL

Le factoriel peut être un problème difficile. Une technique de type carte / réduction - tout comme Google utilise - peut diviser les calculs en interrompant un tas de processus et en collectant les résultats. Cela fera bon usage de tous ces cœurs ou processeurs dans votre système par une froide nuit d'hiver.

Enregistrez sous f.perl et chmod 755 pour vous assurer que vous pouvez l'exécuter. Vous avez installé la liste des déchets pathologiquement éclectiques, n'est-ce pas?

#!/usr/bin/perl -w                                                              
use strict;
use bigint;
die "usage: f.perl N (outputs N!)" unless ($ARGV[0] > 1);
print STDOUT &main::rangeProduct(1,$ARGV[0])."\n";
sub main::rangeProduct {
    my($l, $h) = @_;
    return $l    if ($l==$h);
    return $l*$h if ($l==($h-1));
    # arghhh - multiplying more than 2 numbers at a time is too much work       
    # find the midpoint and split the work up :-)                               
    my $m = int(($h+$l)/2);
    my $pid = open(my $KID, "-|");
      if ($pid){ # parent                                                       
        my $X = &main::rangeProduct($l,$m);
        my $Y = <$KID>;
        chomp($Y);
        close($KID);
        die "kid failed" unless defined $Y;
        return $X*$Y;
      } else {
        # kid                                                                   
        print STDOUT &main::rangeProduct($m+1,$h)."\n";
        exit(0);
    }
}

Trolls:

  • fourches O (log2 (N)) processus
  • ne vérifie pas le nombre de processeurs ou de cœurs dont vous disposez
  • Masque de nombreuses conversions bigint / texte qui se produisent dans chaque processus
  • Une boucle for est souvent plus rapide que ce code
Paul
la source
TIL qu'en perl ARGV[0]est en fait le premier argument et non le script!
ThinkChaos
@plg Je pense que $ 0 pourrait contenir le nom de fichier du script, mais ce n'est pas la même chose que $ ARGV [0]
Paul
Oui, c'est ce que j'ai lu. Je viens de trouver surprenant qu'en perl ce ne soit pas $ARGV[0]parce que la plupart des langues que je connais un peu l'ont
ThinkChaos
4

Python

Juste un algorithme O (n! * N ^ 2) pour trouver la factorielle. Cas de base traité. Pas de débordements.

def divide(n,i):
    res=0
    while n>=i:
         res+=1
         n=n-i
    return res

def isdivisible(n,numbers):
    for i in numbers:
         if n%i!=0:
             return 0
         n=divide(n,i)
    return 1

def factorial(n):
    res = 1
    if n==0: return 1 #Handling the base case
    while not isdivisible(res,range(1,n+1)):
         res+=1
    return res
Sudharsan Mohan
la source
3

Eh bien, il existe une solution simple dans Golfscript. Vous pouvez utiliser un interpréteur Golfscript et exécuter ce code:

.!+,1\{)}%{*}/

Facile hein :) Bonne chance!

Martijn Courteaux
la source
2
Je ne connais pas GolfScript, mais celui-ci me déçoit ... Sur la base des autres exemples GolfScript sur ce site, je m'attendais à ce que la réponse soit!
M. Lister
1
C'est l'opérateur de négation. 0 devient 1 et tout le reste devient 0.
Martijn Courteaux
3

Mathematica

factorial[n_] := Length[Permutations[Table[k, {k, 1, n}]]]

Cela ne semble pas fonctionner pour des nombres supérieurs à 11, et le factoriel [11] a gelé mon ordinateur.

Stephen Montgomery-Smith
la source
3

Rubis

f=->(n) { return 1 if n.zero?; t=0; t+=1 until t/n == f[n-1]; t }

Le one-liner le plus lent que je puisse imaginer. Il faut 2 minutes sur un processeur i7 pour calculer 6!.

réécrit
la source
2

L'approche correcte pour ces problèmes mathématiques difficiles est une DSL. Je vais donc modéliser cela en termes de langage simple

data DSL b a = Var x (b -> a)
             | Mult DSL DSL (b -> a)
             | Plus DSL DSL (b -> a)
             | Const Integer (b -> a) 

Pour bien écrire notre DSL, il est utile de le voir comme une monade gratuite générée par le foncteur algébrique

F X = X + F (DSL b (F X)) -- Informally define + to be the disjoint sum of two sets

Nous pourrions écrire ceci dans Haskell comme

Free b a = Pure a
         | Free (DSL b (Free b a))

Je laisse au lecteur le soin de tirer la mise en œuvre triviale de

join   :: Free b (Free b a) -> Free b a
return :: a -> Free b a
liftF  :: DSL b a -> Free b a

Maintenant, nous pouvons décrire une opération pour modéliser une factorielle dans cette DSL

factorial :: Integer -> Free Integer Integer
factorial 0 = liftF $ Const 1 id
factorial n = do
  fact' <- factorial (n - 1)
  liftF $ Mult fact' n id

Maintenant que nous avons modélisé cela, nous avons juste besoin de fournir une fonction d'interprétation réelle pour notre monade libre.

denote :: Free Integer Integer -> Integer
denote (Pure a) = a
denote (Free (Const 0 rest)) = denote $ rest 0
...

Et je laisse le reste de la dénotation au lecteur.

Pour améliorer la lisibilité, il est parfois utile de présenter un AST concret du formulaire

data AST = ConstE Integer
         | PlusE AST AST
         | MultE AST AST

puis à droite une réflexion triviale

reify :: Free b Integer -> AST

puis il est simple d'évaluer récursivement l'AST.

Daniel Gratzer
la source
2

Python

Vous trouverez ci-dessous une version Python de la solution, qui n'est pas limitée à la limite 32 bits (ou 64 bits sur un système très récent) pour les nombres entiers en Python. Pour contourner cette limitation, nous allons utiliser une chaîne comme entrée et sortie pour la factorialroutine et diviser en interne la chaîne en ses chiffres pour pouvoir effectuer la multiplication.

Voici donc le code: la getDigitsfonction divise une chaîne représentant un nombre en ses chiffres, donc "1234" devient [ 4, 3, 2, 1 ](l'ordre inverse rend simplement les fonctions increaseet multiplyplus simples). La increasefonction prend une telle liste et l'augmente d'une unité. Comme son nom l'indique, la multiplyfonction se multiplie, par exemple multiply([2, 1], [3])retourne [ 6, 3 ]parce que 12 fois 3 est 36. Cela fonctionne de la même manière que vous multiplieriez quelque chose avec un stylo et du papier.

Enfin, la factorialfonction utilise ces fonctions d'aide pour calculer la factorielle réelle, par exemple factorial("9")donne "362880"comme sortie.

import copy

def getDigits(n):
    digits = []
    for c in n:
        digits.append(ord(c) - ord('0'))

    digits.reverse()
    return digits

def increase(d):
    d[0] += 1
    i = 0
    while d[i] >= 10:
        if i == len(d)-1:
            d.append(0)

        d[i] -= 10
        d[i+1] += 1
        i += 1

def multiply(a, b):
    subs = [ ]
    s0 = [ ]
    for bi in b:

        s = copy.copy(s0)
        carry = 0
        for ai in a:
            m = ai * bi + carry
            s.append(m%10)
            carry = m//10

        if carry != 0:
            s.append(carry)

        subs.append(s)
        s0.append(0)

    done = False
    res = [ ]
    termsum = 0
    pos = 0
    while not done:
        found = False
        for s in subs:
            if pos < len(s):
                found = True
                termsum += s[pos]

        if not found:
            if termsum != 0:
                res.append(termsum%10)
                termsum = termsum//10
            done = True
        else:
            res.append(termsum%10)
            termsum = termsum//10
            pos += 1

    while termsum != 0:
        res.append(termsum%10)
        termsum = termsum//10

    return res

def factorial(x):
    if x.strip() == "0" or x.strip() == "1":
        return "1"

    factorial = [ 1 ]
    done = False
    number = [ 1 ]
    stopNumber = getDigits(x)
    while not done:
        if number == stopNumber:
            done = True

        factorial = multiply(factorial, number)
        increase(number)

    factorial.reverse()

    result = ""
    for c in factorial:
        result += chr(c + ord('0'))

    return result

print factorial("9")

Remarques

En python, un entier n'a pas de limite, donc si vous souhaitez le faire manuellement, vous pouvez simplement le faire

fac = 1
for i in range(2,n+1): 
    fac *= i

Il y a aussi le très pratique math.factorial(n) fonction .

Cette solution est évidemment beaucoup plus complexe qu'elle ne devrait l'être, mais elle fonctionne et en fait, elle illustre comment vous pouvez calculer la factorielle au cas où vous seriez limité à 32 ou 64 bits. Donc, même si personne ne croira que c'est la solution que vous avez trouvée pour ce problème simple (au moins en Python), vous pouvez réellement apprendre quelque chose.

brm
la source
Il n'y a pas de limite sur les nombres entiers en Python ... non? Vous devrez peut-être mieux expliquer cela.
Riking
@Riking Oui, en python, il n'y a pas de limite pour les entiers. J'ai ajouté quelques notes pour le rendre plus clair.
brm
2

Python

La solution la plus raisonnable est clairement de vérifier tous les nombres jusqu'à ce que vous trouviez celui qui est la factorielle du nombre donné.

print('Enter the number')
n=int(input())
x=1
while True:
    x+=1
    tempx=int(str(x))
    d=True
    for i in range(1, n+1):
        if tempx/i!=round(tempx/i):
            d=False
        else:
            tempx/=i
    if d:
        print(x)
        break
PygameNerd
la source
2

Une solution récursive la plus élégante en C

Chacun sait que les solutions les plus élégantes aux factorielles sont récursives.

Factorielle:

0! = 1
1! = 1
n! = n * (n - 1)!

Mais la multiplication peut également être définie récursivement comme des ajouts successifs.

Multiplication:

n * 0 = 0
n * 1 = n
n * m = n + n * (m - 1)

Et il en va de même pour les incrémentations successives.

Une addition:

n + 0 = n
n + 1 = (n + 1)
n + m = (n + 1) + (m - 1)

Dans C, nous pouvons utiliser ++xet --xgérer les primitives (x + 1)et (x - 1)respectivement, nous avons donc tout défini.

#include <stdlib.h>
#include <stdio.h>

// For more elegance, use T for the type
typedef unsigned long T;

// For even more elegance, functions are small enough to fit on one line

// Addition
T A(T n, T m) { return (m > 0)? A(++n, --m) : n; }

// Multiplication
T M(T n, T m) { return (m > 1)? A(n, M(n, --m)): (m? n: 0); }

// Factorial
T F(T n) { T m = n; return (m > 1)? M(n, F(--m)): 1; }

int main(int argc, char **argv)
{
    if (argc != 2)
        return 1;

    printf("%lu\n", F(atol(argv[1])));

    return 0;
}

Essayons-le:

$ ./factorial 0
1
$ ./factorial 1
1
$ ./factorial 2
2
$ ./factorial 3
6
$ ./factorial 4
24
$ ./factorial 5
120
$ ./factorial 6
720
$ ./factorial 7
5040
$ ./factorial 8
40320

Parfait, bien que 8! a pris beaucoup de temps pour une raison quelconque. Eh bien, les solutions les plus élégantes ne sont pas toujours les plus rapides. Nous allons continuer:

$ ./factorial 9

Hmm, je vous préviendrai quand il reviendra ...


la source
2

Python

Comme l'indique la réponse de @ Matt_Sieker, les factorielles peuvent être divisées en plus - pourquoi, la répartition des tâches est l'essence de la programmation. Mais, nous pouvons décomposer cela en addition par 1!

def complicatedfactorial(n):
    def addby1(num):
        return num + 1
    def addnumbers(a,b):
        copy = b
        cp2 = a
        while b != 0:
            cp2 = addby1(cp2)
            b -= 1
    def multiply(a,b):
        copy = b
        cp2 = a
        while b != 0:
            cp2 = addnumbers(cp2,cp2)
    if n == 0:
        return 1
    else:
        return multiply(complicatedfactorial(n-1),n)

Je pense que ce code garantit une erreur SO, car

  1. Récursion - réchauffe

  2. Chaque couche génère des appels à se multiplier

  3. qui génère des appels vers des numéros supplémentaires

  4. qui génère des appels à addby1!

Trop de fonctions, non?

Dan l'homme
la source
1

TI-Basic 84

:yumtcInputdrtb@gmail And:cReturnbunchojunk@Yahoo A!op:sEnd:theemailaddressIS Crazy ANSWER LOL

Ça marche vraiment :)

Timtech
la source
1

Javascript

De toute évidence, le travail d'un programmeur est de faire le moins de travail possible et d'utiliser autant de bibliothèques que possible. Nous voulons donc importer jQuery et math.js . Maintenant, la tâche est simple comme ceci:

$.alert=function(message){
    alert(message);
}$.factorial=function(number){
    alert(math.eval(number+"!"));
    return math.eval(number+"!");
}
$.factorial(10);
scrblnrd3
la source
1

Python

Avec juste une légère modification de l'implémentation factorielle récursive standard, elle devient intolérablement lente pour n> 10.

def factorial(n):
    if n in (0, 1):
        return 1
    else:
        result = 0
        for i in range(n):
            result += factorial(n - 1)
        return result
dan04
la source
1

Frapper

#! /bin/bash

function fact {
    if [[ ${1} -le 1 ]]; then
        return 1
    fi;

    fact $((${1} - 1))
    START=$(date +%s)
    for i in $(seq 1 $?); do sleep ${1}; done
    END=$(date +%s)
    RESULT=$(($END - $START))
    return $RESULT
}

fact ${1}
echo $?
alaroldai
la source
1

Essayons de le faire par la méthode Monte Carlo . Nous savons tous que la probabilité que deux n- permutations aléatoires soient égales est exactement de 1 / n! . Par conséquent, nous pouvons simplement vérifier combien de tests sont nécessaires (appelons ce numéro b ) jusqu'à ce que nous obtenions c hits. Alors, n! ~ b / c .

Sage, devrait aussi fonctionner en Python

def RandomPermutation(n) :           
    t = range(0,n)                   
    for i in xrange(n-1,0,-1):       
        x = t[i]                     
        r = randint(0,i)             
        t[i] = t[r]                  
        t[r] = x                     
    return t                         

def MonteCarloFactorial(n,c) :   
    a = 0                            
    b = 0                            
    t = RandomPermutation(n)         
    while a < c :                
        t2 = list(t)                 
        t = RandomPermutation(n)     
        if t == t2 :                 
            a += 1                   
        b += 1                       
    return round(b/c)            

MonteCarloFactorial(5,1000)
# returns an estimate of 5!
yo '
la source
1

frapper

Les factorielles sont facilement déterminées avec des outils de ligne de commande bien connus de bash.

read -p "Enter number: " $n
seq 1 $n | xargs echo | tr ' ' '*' | bc

Comme @Aaron Davies l'a mentionné dans les commentaires, cela semble beaucoup plus ordonné et nous voulons tous un programme agréable et bien rangé, n'est-ce pas?

read -p "Enter number: " $n
seq 1 $n | paste -sd\* | bc
jippie
la source
1
je recommande la pastecommande très sous-estimée :seq 1 $n | paste -sd\* | bc
Aaron Davies
2
@AaronDavies pasteressemble à un mot anglais ordinaire et facile à retenir. Voulez-vous vraiment ça? ; o)
jippie