97 votes

Fonction factorielle en Ruby

Je suis en train de devenir fou : Où est la fonction Ruby pour la factorielle ? Non, je n'ai pas besoin de tutoriels d'implémentation, je veux juste la fonction de la bibliothèque. Ce n'est pas dans Math !

Je commence à douter, est-ce une fonction de la bibliothèque standard ?

66 votes

Je le fais comme 6.downto(1).inject(:*)

46 votes

@mckeed : Ou (1..6).inject(:*) qui est un peu plus succinct.

0 votes

@sepp2k : bien sûr, mais je préfère avoir le numéro sur lequel j'agis à l'avant pour plus de lisibilité.

140voto

sepp2k Points 157757

Il n'y a pas de fonction factorielle dans la bibliothèque standard.

9 votes

Ruby a le Math.gamma méthode, par exemple stackoverflow.com/a/37352690/407213

2 votes

Quelle logique folle ! On a la fonction (n-1) ! et on n'a pas la fonction n ! ! !!

120voto

Comme si c'était mieux

(1..n).inject(:*) || 1

37 votes

Ou spécifier directement la valeur initiale : (1..n).reduce(1, :*) .

77voto

Elle ne fait pas partie de la bibliothèque standard mais vous pouvez étendre la classe Integer.

class Integer
  def factorial_recursive
    self <= 1 ? 1 : self * (self - 1).factorial
  end
  def factorial_iterative
    f = 1; for i in 1..self; f *= i; end; f
  end
  alias :factorial :factorial_iterative
end

N.B. La factorielle itérative est un meilleur choix pour des raisons évidentes de performance.

8 votes

Il a explicitement dit qu'il ne voulait pas de mise en œuvre.

118 votes

Il ne le fera peut-être pas, mais les personnes qui recherchent "Ruby factorial" dans SO le feront peut-être.

1 votes

rosettacode.org/wiki/Factorial#Ruby est tout simplement faux. Il n'y a pas de cas pour 0

29voto

fearless_fool Points 9190

Copié sans vergogne de http://rosettacode.org/wiki/Factorial#Ruby mon préféré est

class Integer
  def fact
    (1..self).reduce(:*) || 1
  end
end

>> 400.fact
=> 64034522846623895262347970319503005850702583026002959458684445942802397169186831436278478647463264676294350575035856810848298162883517435228961988646802997937341654150838162426461942352307046244325015114448670890662773914918117331955996440709549671345290477020322434911210797593280795101545372667251627877890009349763765710326350331533965349868386831339352024373788157786791506311858702618270169819740062983025308591298346162272304558339520759611505302236086810433297255194852674432232438669948422404232599805551610635942376961399231917134063858996537970147827206606320217379472010321356624613809077942304597360699567595836096158715129913822286578579549361617654480453222007825818400848436415591229454275384803558374518022675900061399560145595206127211192918105032491008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Cette implémentation se trouve également être la plus rapide parmi les variantes répertoriées dans Rosetta Code.

mise à jour #1

Ajouté || 1 pour traiter le cas zéro.

mise à jour n°2

Avec nos remerciements et notre reconnaissance à Mark Thomas Voici une version un peu plus efficace, élégante et obscure :

class Integer
  def fact
    (2..self).reduce(1,:*)
  end
end

1 votes

Qu'est ce que ça veut dire ?! oui c'est rapide mais c'est très peu convivial par contre

3 votes

C'est aussi incorrect pour 0 ! - devrait être quelque chose comme : if self <= 1 ; 1 ; else ; (1..self).reduce(:*) ; end

9 votes

@allen - Ne blâmez pas la langue si vous ne pouvez pas la comprendre. Cela signifie simplement qu'il faut prendre l'intervalle 1 à self, puis en retirer le premier élément (1) (c'est ce que signifie reduce en programmation fonctionnelle). Ensuite, enlevez le premier élément de ce qui reste (2) et multipliez (:*) ces éléments ensemble. Retirez ensuite le premier élément de ce qui reste (3) et multipliez-le avec le total courant. Continuez jusqu'à ce qu'il ne reste plus rien (c'est-à-dire que vous avez traité toute la plage). Si reduce échoue (parce que le tableau est vide dans le cas de 0 !), il suffit de retourner 1 de toute façon.

14voto

Vous pouvez également utiliser Math.gamma qui se résume à la factorielle pour les paramètres entiers.

3 votes

Extrait de la documentation : "Notez que gamma(n) est identique à fact(n-1) pour les entiers n > 0. Cependant, gamma(n) renvoie un flottant et peut être une approximation". Si l'on prend cela en compte, cela fonctionne, mais la solution de réduction semble beaucoup plus simple.

0 votes

Merci pour cela ! Mon instinct me dit d'utiliser la bibliothèque standard plutôt qu'une réduction écrite sur mesure chaque fois que c'est possible. Le profilage pourrait suggérer le contraire.

2 votes

Note : C'est O(1) et précis pour 0..22 : MRI Ruby effectue en fait une recherche pour ces valeurs (voir static const double fact_table[] dans le source ). Au-delà, c'est une approximation. 23 !, par exemple, nécessite une mantisse de 56 bits qu'il est impossible de représenter précisément en utilisant le double IEEE 754 qui a une mantisse de 53 bits.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X