[英]How to make perfect power algorithm more efficient?
我有以下代碼:
def isPP(n):
pos = [int(i) for i in range(n+1)]
pos = pos[2:] ##to ignore the trivial n** 1 == n case
y = []
for i in pos:
for it in pos:
if i** it == n:
y.append((i,it))
#return list((i,it))
#break
if len(y) <1:
return None
else:
return list(y[0])
由於我在內存中存儲了太多內存,因此直到2000年為止,它都能完美運行。 我該怎么做才能使它有效地處理大量數字(例如50000或100000)。 在找到一種情況后,我試圖使其結束,但是如果數量很大,我的算法仍然效率太低。
有小費嗎?
IIRC,迭代檢查“它有平方根嗎?有立方根嗎?有第四個根嗎?……”要容易得多,您很快就會得出推定的根必須在1
之間的觀點。和2
,此時您可以停止。
如果存在b和e且b ^ e = n,則數字n是理想冪。 例如216 = 6 ^ 3 = 2 ^ 3 * 3 ^ 3是一個完美的冪,但72 = 2 ^ 3 * 3 ^ 2不是一個完美的冪。
確定一個數字是否為完美冪的訣竅是要知道,如果該數字是一個完美冪,則指數e必須小於log2 n ,因為如果e大於2,則e將大於n 。 此外,僅需測試素數es ,因為如果數字是復合指數的完美冪,那么它也是復合成分的質數的完美冪; 例如2 ^ 15 = 32768 = 32 ^ 3 = 8 ^ 5是理想的立方根,也是理想的第五根。
下面顯示的功能isPerfectPower
通過首先使用牛頓方法計算整數根,然后對結果加冪以檢查其是否等於n,來測試每個小於log2 n的素數。 輔助函數質數通過Eratosthenes的Sieve計算primes
列表, iroot
通過牛頓方法計算整數k th-root, ilog
通過二進制搜索計算以b為底的整數對數。
def primes(n): # sieve of eratosthenes
i, p, ps, m = 0, 3, [2], n // 2
sieve = [True] * m
while p <= n:
if sieve[i]:
ps.append(p)
for j in range((p*p-3)/2, m, p):
sieve[j] = False
i, p = i+1, p+2
return ps
def iroot(k, n): # assume n > 0
u, s, k1 = n, n+1, k-1
while u < s:
s = u
u = (k1 * u + n // u ** k1) // k
return s
def ilog(b, n): # max e where b**e <= n
lo, blo, hi, bhi = 0, 1, 1, b
while bhi < n:
lo, blo, hi, bhi = hi, bhi, hi+hi, bhi*bhi
while 1 < (hi - lo):
mid = (lo + hi) // 2
bmid = blo * pow(b, (mid - lo))
if n < bmid: hi, bhi = mid, bmid
elif bmid < n: lo, blo = mid, bmid
else: return mid
if bhi == n: return hi
return lo
def isPerfectPower(n): # x if n == x ** y, or False
for p in primes(ilog(2,n)):
x = iroot(p, n)
if pow(x, p) == n: return x
return False
在我的博客上還有關於完美功率謂詞的進一步討論。
一個相關的改進將是:
import math
def isPP(n):
# first have a look at the length of n in binary representation
ln = int(math.log(n)/math.log(2)) + 1
y = []
for i in range(n+1):
if (i <= 1):
continue
# calculate max power
li = int(math.log(i)/math.log(2))
mxi = ln / li + 1
for it in range(mxi):
if (it <= 1):
continue
if i ** it == n:
y.append((i,it))
# break if you only need 1
if len(y) <1:
return None
else:
return list(y[0])
我認為更好的方法是實施此“ hack”:
import math
def isPP(n):
range = math.log(n)/math.log(2)
range = (int)(range)
result = []
for i in xrange(n):
if(i<=1):
continue
exponent = (int)(math.log(n)/math.log(i))
for j in [exponent-1, exponent, exponent+1]:
if i ** j == n:
result.append([i,j])
return result
print isPP(10000)
結果:
[[10,4],[100,2]]
黑客使用以下事實:
if log(a)/log(b) = c,
then power(b,c) = a
由於此計算在浮點數上可能會略微不足以給出真正近似的結果,因此將指數檢查為+/- 1
的精度。
您可以進行必要的調整以處理n=1, etc.
極端情況n=1, etc.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.