Algoritma terbaik yang dikenal adalah untuk mengekspresikan faktorial sebagai produk kekuatan utama. Seseorang dapat dengan cepat menentukan bilangan prima serta kekuatan yang tepat untuk setiap bilangan prima menggunakan pendekatan saringan. Komputasi setiap daya dapat dilakukan secara efisien menggunakan kuadrat ulang, dan kemudian faktor-faktor tersebut dikalikan bersama. Ini dijelaskan oleh Peter B. Borwein, On Complexity of Calculating Factorials , Journal of Algorithms 6 376-380, 1985. ( PDF ) Singkatnya, dapat dihitung dalam waktu O ( n ( log n ) 3 log log n ) , dibandingkan dengan Ω ( nn !O ( n ( logn )3loglogn ) waktu yang diperlukan saat menggunakan definisi.Ω ( n2logn )
Apa yang mungkin dimaksud buku teks adalah metode membagi dan menaklukkan. Satu dapat mengurangi perkalian dengan menggunakan pola reguler dari produk.n - 1
Biarkan menyatakan 1 ⋅ 3 ⋅ 5 ⋯ ( 2 n - 1 ) sebagai notasi yang mudah. Susun ulang faktor-faktor ( 2 n ) ! = 1 ⋅ 2 ⋅ 3 ⋯ ( 2 n ) sebagai
( 2 n ) ! = n ! ⋅ 2 n ⋅ 3 ⋅ 5 ⋅ 7 ⋯ ( 2 n -n ?1 ⋅ 3 ⋅ 5 ⋯ ( 2 n - 1 )( 2 n ) ! = 1 ⋅ 2 ⋅ 3 ⋯ ( 2 n )
Sekarang anggaplah n = 2 k untuk beberapa bilangan bulat k > 0 . (Ini adalah asumsi yang berguna untuk menghindari komplikasi dalam diskusi berikut, dan idenya dapat diperluas ke n umum.) Kemudian ( 2 k ) ! = ( 2 k - 1 ) ! 2 2 k - 1 ( 2 k - 1 ) ? dan dengan memperluas pengulangan ini,
( 2 k ) ! =
( 2 n ) ! = n ! ⋅ 2n⋅ 3 ⋅ 5 ⋅ 7 ⋯ ( 2 n - 1 ) .
n = 2kk > 0n( 2k) ! = ( 2k - 1) ! 22k - 1( 2k - 1) ?
Komputasi
(2k-dan mengalikan produk parsial pada setiap tahap membutuhkan
(k-2)+2k-1( 2k) ! = ( 22k - 1+ 2k - 2+ ⋯ + 20) ∏i = 0k - 1( 2saya) ? = ( 22k- 1) ∏i = 1k - 1( 2saya) ? .
( 2k - 1) ? perkalian. Ini merupakan peningkatan faktor hampir
2 dari
2 k - 2 perkalian hanya menggunakan definisi. Beberapa operasi tambahan diperlukan untuk menghitung kekuatan
2 , tetapi dalam aritmatika biner ini dapat dilakukan dengan murah (tergantung pada apa yang dibutuhkan secara tepat, mungkin hanya perlu menambahkan akhiran
2 k - 1 nol).
( k - 2 ) + 2k - 1- 222k- 222k- 1
Kode Ruby berikut mengimplementasikan versi yang disederhanakan ini. Ini tidak menghindari menghitung ulang bahkan di mana ia bisa melakukannya: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)
Bahkan kode first-pass ini meningkat pada hal yang sepele
f = 1; (1..32768).map{ |i| f *= i }; print f
sekitar 20% dalam pengujian saya.
Dengan sedikit kerja, ini dapat ditingkatkan lebih lanjut, juga menghilangkan persyaratan bahwa menjadi kekuatan 2 (lihat diskusi ekstensif ).n2