给定n的函数的所有实际值的总和

时间:2019-11-22 18:29:27

标签: math greatest-common-divisor

对于给定的n,我如何有效地求出totient函数的所有实际值的总和。 例如tot(10)是1,3,7,9 => 1 + 3 + 7 + 9 = 20。 我在下面尝试了蛮力方法

out1 <- paste(dQuote(myVars, q = FALSE), "=rnorm(5)", sep="", collapse=", ")
cat(out1, '\n')
#"var1"=rnorm(5), "var2"=rnorm(5), "var3"=rnorm(5), "var4"=rnorm(5), "var5"=rnorm(5) 

是O(nxlog(n))。 log(n)用于每一步的gcd计算。
限制条件:1 <= n <= 10 ^ 6。
如果有更好的解决方案?

1 个答案:

答案 0 :(得分:0)

如果打印出该函数的第一个值,则会得到:

1、1、3、4、10、6、21、16、27、20、55、24、78、42、60、64、136,...

oeis中查找该函数,您发现A023896:“ n的总和,即,最多n个整数和互素为n的和”。然后我们得到一个公式:
n*phi(n)/2以外的n=1phi是欧拉的totient function,欧拉本人对此表示了一种快速的计算方法:n * Product_{distinct primes p dividing n} (1 - 1/p)

将所有内容放到一些纯Python函数中:

import math

def prime_factors(n):
    if n == 1:
        return []
    if n % 2 == 0:
        return [2] + prime_factors(n//2)
    if n % 3 == 0:
        return [3] + prime_factors(n//3)
    if n % 5 == 0:
        return [5] + prime_factors(n//5)
    for i in range(6, int(math.sqrt(n)) + 1, 6):
        if n % (i + 1) == 0:
            return [i + 1] + prime_factors(n // (i + 1))
        if n % (i + 5) == 0:
            return [i + 5] + prime_factors(n // (i + 5))
    return [n]

def gcd(a,b):
    if b == 0:
        return a
    return gcd(b, a % b)

def totative_sum(n):
    s = 0
    for i in range(1, n+1):
        if gcd(n, i) == 1:
            s += i
    return s

def phi(n):
    prod = n
    for i in set(prime_factors(n)): # convert to a set, because we don't want duplicates
        # prod = prod * (1 - 1 / i)
        prod = prod * (i - 1) // i  # rewrite the formula to only work with integers
    return int(prod)

def fast_totative_sum(n):
    if n == 1:
        return 1
    return n * phi(n) // 2

print([totative_sum(n) for n in range(1, 31)])
print([fast_totative_sum(n) for n in range(1, 31)])

n = 12345678
print(fast_totative_sum(n))
print(totative_sum(n))

输出:

[1, 1, 3, 4, 10, 6, 21, 16, 27, 20, 55, 24, 78, 42, 60, 64, 136, 54, 171, 80, 126, 110, 253, 96, 250, 156, 243, 168, 406, 120]
24860442405888

请注意,此处的素数分解仅逐步遍历6k + 1和6k + 5的可能因子。甚至可以进一步优化,以模30步进,其中仅需要测试8个因数,而可以跳过22个。 (依此类推,取模210 = 2 * 3 * 5 * 7等。)

如果需要计算大量数字的素因子,则可以构建Eratosthenes筛子并将结果保存在列表中。这样,您只需要逐步检查素数即可找到素因数。