我需要在here的第一个答案中对编辑中建议的程序进行说明。这是一个程序,可以找到一系列数字的总和。有人可以提供一个简单的解释吗? (暂时忽略求和部分,我需要找出 init 方法如何找到总数。)我知道答案中有一个解释,但这是对不同程序的解释,我需要这个特定的解释。
class Totient:
def __init__(self, n):
self.totients = [1 for i in range(n)]
for i in range(2, n):
if self.totients[i] == 1:
for j in range(i, n, i):
self.totients[j] *= i - 1
k = j / i
while k % i == 0:
self.totients[j] *= i
k /= i
def __call__(self, i):
return self.totients[i]
if __name__ == '__main__':
from itertools import imap
totient = Totient(10000)
print sum(imap(totient, range(10000)))
答案 0 :(得分:1)
这是Eratosthenes筛选的一个变种,用于寻找素数。
如果您想知道单个数字 n 的总数,找到它的最佳方法是计算 n 并将每个因子的乘积减去1 ;例如,30 = 2 * 3 * 5,并从每个因子中减1,然后乘以,给出1 * 2 * 4 = 8的总数。但是如果你想找到小于给定 n ,比分解每种方法更好的方法是筛分。想法很简单:设置一个数组 X 从0到 n ,在每个 X i中存储 i ,然后从0开始遍历数组,每当 X i = i 循环遍历的倍数时我,将每个乘以 i - 1。
my blog的进一步讨论和代码。
答案 1 :(得分:1)
我不完全确定代码在做什么 - 但坦率地说它看起来很糟糕。它显然试图使用Euler的totient函数是乘法的,这意味着a,b是相对素数,然后t(a,b)= t(a)* t(b),以及如果p是素数然后t(p)= p-1。但是 - 它似乎正在使用原始的试验部门来确定这些事情。如果你真的想要计算给定范围内所有数字的总数,那么你应该使用一个算法来筛选数字。
这是一个版本,它随着它的进行筛选并利用了剑柄的倍增性质。在每次通过主循环时,它以一个尚未处理的素数p开始。它确定p <= n的所有幂,然后使用这些幂的直接公式(见https://en.wikipedia.org/wiki/Euler%27s_totient_function)。一旦添加了这些总数,它就形成所有可能的产品&lt; = n这些权力以及先前已计算过总数的数字。这样就可以将大量数字添加到先前确定的数字列表中。最多需要通过主循环进行sqrt(n)次传递。它几乎立即运行n = 10000.它返回一个列表,其中第i个值是i的总和(为方便起见,t(0)= 0):
def allTotients(n):
totients = [None]*(n+1) #totients[i] will contain the t(i)
totients[0] = 0
totients[1] = 1
knownTotients = [] #known in range 2 to n
p = 2
while len(knownTotients) < n - 1:
powers = [p]
k = 2
while p ** k <= n:
powers.append(p ** k)
k +=1
totients[p] = p - 1
for i in range(1,len(powers)):
totients[powers[i]] = powers[i] - powers[i-1]
#at this stage powers represent newly discovered totients
#combine with previously discovered totients to get still more
newTotients = powers[:]
for m in knownTotients:
for pk in powers:
if m*pk > n: break
totients[m*pk] = totients[m]*totients[pk]
newTotients.append(m*pk)
knownTotients.extend(newTotients)
#if there are any unkown totients -- the smallest such will be prime
if len(knownTotients) < n-1:
p = totients.index(None)
return totients
为了完整起见,这里有一个算法的Python实现,用于计算用户448810在答案中描述的单个数字的总数:
from math import sqrt
#crude factoring algorithm:
small_primes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,
53,59,61,67,71,73,79,83,89,97]
def factor(n):
#returns a list of prime factors
factors = []
num = n
#first pull out small prime factors
for p in small_primes:
while num % p == 0:
factors.append(p)
num = num // p
if num == 1: return factors
#now do trial division, starting at 101
k = 101
while k <= sqrt(num):
while num % k == 0:
factors.append(k)
num = num // k
k += 2
if num == 1:
return factors
else:
factors.append(num)
return factors
def totient(n):
factors = factor(n)
unique_factors = set()
t = 1
for p in factors:
if p in unique_factors:
t *= p
else:
unique_factors.add(p)
t *= (p-1)
return t