Der beste Algorithmus, der bekannt ist, besteht darin, die Fakultät als Produkt der Primkräfte auszudrücken. Mit einem Siebansatz kann man schnell die Primzahlen sowie die richtige Leistung für jede Primzahl bestimmen. Die Berechnung jeder Potenz kann durch wiederholtes Quadrieren effizient durchgeführt werden, und dann werden die Faktoren miteinander multipliziert. Dies wurde von Peter B. Borwein, Über die Komplexität von Rechenfaktoren , Journal of Algorithms 6 376–380, 1985, beschrieben. ( PDF ) Kurz gesagt,kann in berechnet werden, verglichen mit der bei Verwendung der Definition erforderlichen -Zeit.n !O ( n ( logn )3LogLogn )Ω ( n2Logn )
Was das Lehrbuch vielleicht bedeutete, war die Divide-and-Conquer-Methode. Man kann die Multiplikationen reduzieren, indem man das reguläre Muster des Produkts verwendet.n - 1
LassenBezeichnen Sie als geeignete Schreibweise. Ordne die Faktoren von als
Nehmen wir nun an, dass für eine ganze Zahl . (Dies ist eine nützliche Annahme, um Komplikationen in der folgenden Diskussion zu vermeiden, und die Idee kann auf das allgemeine .) Dannund indem Sie diese Wiederholung erweitern,
Rechnen1 ⋅ 3 ⋅ 5 ⋯ ( 2 n - 1 ) ( 2 n ) ! = 1 ≤ 2 ≤ 3 ≤ ( 2 n ) ( 2 n ) ! = n ! ≤ 2 n ≤ 3 ≤ 5 ≤ 7 ≤ ( 2 n - 1 ) . n = 2 k k >n ?1 ⋅ 3 ⋅ 5 ⋯ ( 2 n - 1 )( 2 n ) ! = 1 ≤ 2 ≤ 3 ≤ ( 2 n )
( 2 n ) ! = n ! ⋅ 2n≤ 3 ≤ 5 ≤ 7 ≤ ( 2 n - 1 ) .
n = 2kn ( 2 k ) ! = ( 2 k - 1 ) ! 2 2 k - 1 ( 2 k - 1 ) ? ( 2 k ) ! = ( 2 2 k - 1 + 2 k - 2 + ⋯ + 2 0 ) k - 1 ∏ i = 0 ( 2 i )k > 0n( 2k) ! = ( 2k - 1) ! 22k - 1( 2k - 1) ?( 2 k & ndash ; 1 ) & dgr ; ( K - 2 ) + 2 k - 1 - 2 2 2 k - 2 2 2 k - 1( 2k) ! = ( 22k - 1+ 2k - 2+ ⋯ + 20) ∏i = 0k - 1( 2ich) ? = ( 22k- 1) ∏i = 1k - 1( 2ich) ? .
( 2k - 1) ?und das Multiplizieren der Teilprodukte in jeder Stufe ergibt Multiplikationen. Dies ist eine Verbesserung um einen Faktor von fast gegenüber Multiplikationen unter Verwendung der Definition. Einige zusätzliche Operationen sind erforderlich, um die Potenz von zu berechnen , aber in der Binärarithmetik kann dies kostengünstig durchgeführt werden (je nachdem, was genau erforderlich ist, muss möglicherweise nur ein Suffix von Nullen hinzugefügt werden ).
( k - 2 ) + 2k - 1- 222k- 222k- 1
Der folgende Ruby-Code implementiert eine vereinfachte Version davon. Dies vermeidet nicht die Neuberechnung vonsogar wo es das könnte: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)
Auch dieser First-Pass-Code verbessert das Triviale
f = 1; (1..32768).map{ |i| f *= i }; print f
um etwa 20% in meinen Tests.
Mit ein wenig Arbeit kann dies weiter verbessert werden, und es entfällt auch die Anforderung, dass eine Potenz von (siehe die ausführliche Diskussion ).2n2