Python 3、高度なアルゴリズム、Peter Luschny:8.25x(1 280 000/155 000)
Peter Luschnyから恥知らずにコピー、http: //www.luschny.de/math/factorial/FastFactorialFunctions.htm
、
「クリエイティブ・コモンズ表示-継承3.0」ライセンスの下でこのコードを提供します。
これは実際には非常に高度なアルゴリズムで、「スイング階乗」と呼ばれるものと素数のリストを使用します。他の多くの回答と同様に、32ビット整数でほとんどの乗算を実行すると、さらに高速になると思います。
#! /usr/bin/python3
import time
import bisect
def Primes(n) :
primes = [2, 3]
lim, tog = n // 3, False
composite = [False for i in range(lim)]
d1 = 8; d2 = 8; p1 = 3; p2 = 7; s = 7; s2 = 3; m = -1
while s < lim : # -- scan the sieve
m += 1 # -- if a prime is found
if not composite[m] : # -- cancel its multiples
inc = p1 + p2
for k in range(s, lim, inc) : composite[k] = True
for k in range(s + s2, lim, inc) : composite[k] = True
tog = not tog
if tog: s += d2; d1 += 16; p1 += 2; p2 += 2; s2 = p2
else: s += d1; d2 += 8; p1 += 2; p2 += 6; s2 = p1
k, p, tog = 0, 5, False
while p <= n :
if not composite[k] : primes.append(p)
k += 1;
tog = not tog
p += 2 if tog else 4
return primes
def isqrt(x):
'''
Writing your own square root function
'''
if x < 0: raise ValueError('square root not defined for negative numbers')
n = int(x)
if n == 0: return 0
a, b = divmod(n.bit_length(), 2)
x = 2**(a + b)
while True:
y = (x + n // x) // 2
if y >= x: return x
x = y
def product(s, n, m):
if n > m: return 1
if n == m: return s[n]
k = (n + m) // 2
return product(s, n, k) * product(s, k + 1, m)
def factorialPS(n):
small_swing = [1,1,1,3,3,15,5,35,35,315,63,693,231,3003,429,6435,6435,
109395,12155,230945,46189,969969,88179,2028117,676039,16900975,
1300075,35102025,5014575,145422675,9694845,300540195,300540195]
def swing(m, primes):
if m < 33: return small_swing[m]
s = bisect.bisect_left(primes, 1 + isqrt(m))
d = bisect.bisect_left(primes, 1 + m // 3)
e = bisect.bisect_left(primes, 1 + m // 2)
g = bisect.bisect_left(primes, 1 + m)
factors = primes[e:g]
factors += filter(lambda x: (m // x) & 1 == 1, primes[s:d])
for prime in primes[1:s]:
p, q = 1, m
while True:
q //= prime
if q == 0: break
if q & 1 == 1:
p *= prime
if p > 1: factors.append(p)
return product(factors, 0, len(factors) - 1)
def odd_factorial(n, primes):
if n < 2: return 1
return (odd_factorial(n // 2, primes)**2) * swing(n, primes)
def eval(n):
if n < 0:
raise ValueError('factorial not defined for negative numbers')
if n == 0: return 1
if n < 20: return product(range(2, n + 1), 0, n-2)
N, bits = n, n
while N != 0:
bits -= N & 1
N >>= 1
primes = Primes(n)
return odd_factorial(n, primes) * 2**bits
return eval(n)
start = time.time()
answer = factorialPS(1280000)
print(time.time()-start)
operator.mul
ラムダ関数の代わりに