Le meilleur algorithme connu consiste à exprimer la factorielle en tant que produit de puissances premières. On peut rapidement déterminer les nombres premiers ainsi que la bonne puissance pour chaque nombre premier en utilisant une approche par tamis. Le calcul de chaque puissance peut être effectué efficacement en utilisant des quadrillages répétés, puis les facteurs sont multipliés ensemble. Ceci a été décrit par Peter B. Borwein, De la complexité des facteurs de calcul , Journal of Algorithms 6 376–380, 1985. ( PDF ) En bref,peut être calculé en temps , comparé au temps requis pour l’utilisation de la définition.n!O(n(logn)3loglogn)Ω(n2logn)
Le manuel a peut-être voulu dire que c'était la méthode diviser pour régner. On peut réduire les multiplications en utilisant le motif régulier du produit.n−1
Letnotez comme une notation pratique. Réarrangez les facteurs de tant que
Supposons maintenant que pour un nombre entier . (Ceci est une hypothèse utile pour éviter des complications dans la discussion suivante, et l'idée peut être étendue au général .) Alorset en élargissant cette récurrence,
Informatique1 ⋅ 3 ⋅ 5 ⋯ ( 2 n - 1 ) ( 2 n ) ! = 1 ⋅ 2 ⋅ 3 ⋯ ( 2 n ) ( 2 n ) ! = n ! ⋅ 2 n ⋅ 3 ⋅ 5 ⋅ 0 n ( 2 k ) ! = ( 2 k - 1 ) !n?1⋅3⋅5⋯(2n−1)(2n)!=1⋅2⋅3⋯(2n)n = 2 k k >
(2n)!=n!⋅2n⋅3⋅5⋅7⋯(2n−1).
n=2kk>0n( 2 k ) ! = ( 2 2 k - 1 + 2 k - 2 + ⋯ + 2 0 ) k - 1 Π i = 0 ( 2 i )( 2k) ! = ( 2k - 1) ! 22k - 1( 2k - 1) ?( 2 k - 1 ) ? ( k - 2 ) + 2 k - 1 - 2 2 2 2 k - 2 2 2 k - 1( 2k) ! = ( 22k - 1+ 2k - 2+ ⋯ + 20) Πi = 0k - 1( 2je) ? = ( 22k- 1) Πi = 1k - 1( 2je) ? .
( 2k - 1) ?et multiplier les produits partiels à chaque étape prend multiplications. Il s’agit d’une amélioration d’un facteur de près de sur multiplications en utilisant simplement la définition. Quelques opérations supplémentaires sont nécessaires pour calculer la puissance de , mais en arithmétique binaire, cela peut être effectué à moindre coût (selon ce qui est requis, il suffit d'ajouter un suffixe de zéros).
( k - 2 ) + 2k - 1- 222k- 222k- 1
Le code Ruby suivant implémente une version simplifiée de cela. Cela n'évite pas de recalculermême où il pourrait le faire:n ?
def oddprod(l,h)
p = 1
ml = (l%2>0) ? l : (l+1)
mh = (h%2>0) ? h : (h-1)
while ml <= mh do
p = p * ml
ml = ml + 2
end
p
end
def fact(k)
f = 1
for i in 1..k-1
f *= oddprod(3, 2 ** (i + 1) - 1)
end
2 ** (2 ** k - 1) * f
end
print fact(15)
Même ce code de premier passage améliore la trivialité
f = 1; (1..32768).map{ |i| f *= i }; print f
d'environ 20% lors de mes tests.
Avec un peu de travail, cela peut encore être amélioré, en supprimant également la nécessité que soit une puissance de (voir la discussion approfondie ).2n2