你将如何实现除数函数?

时间:2013-01-16 13:49:31

标签: python math numbers

divisor function是自然数的除数之和。

进行一些研究我发现this是一个非常好的方法,如果你想找到给定自然数N的除数函数,所以我试着用Python编写代码:

def divisor_function(n):
    "Returns the sum of divisors of n"
    checked = [False]*100000
    factors = prime_factors(n)
    sum_of_divisors = 1 # It's = 1 because it will be the result of a product
    for x in factors:
        if checked[x]:
            continue
        else:
            count = factors.count(x)
            tmp = (x**(count+1)-1)//(x-1)
            sum_of_divisors*=tmp
            checked[x]=True
    return sum_of_divisors

它工作得很好,但我确信它可以改进(例如:我创建一个包含100000元素的列表,但我没有使用大多数元素。)

您将如何改进/实施它?

P.S。这是prime_factors

def prime_factors(n):
    "Returns all the prime factors of a positive integer"
    factors = []
    d = 2
    while (n > 1):
        while (n%d==0):
            factors.append(d)
            n /= d
        d = d + 1
        if (d*d>n):
            if (n>1): factors.append(int(n));
            break;
    return factors

5 个答案:

答案 0 :(得分:8)

计算除数之和时,需要 p 1 k < k < sub> 1 p 2 k 2 ... - 也就是说,你需要分解中每个素数的指数。目前,您通过计算素数因子的平面列表来执行此操作,然后调用count来计算指数。这是浪费时间,因为您可以首先以您需要的格式轻松生成素数分解,如下所示:

def factorization(n):
    """
    Generate the prime factorization of n in the form of pairs (p, k)
    where the prime p appears k times in the factorization.

    >>> list(factorization(1))
    []
    >>> list(factorization(24))
    [(2, 3), (3, 1)]
    >>> list(factorization(1001))
    [(7, 1), (11, 1), (13, 1)]
    """
    p = 1
    while p * p < n:
        p += 1
        k = 0
        while n % p == 0:
            k += 1
            n //= p
        if k:
            yield p, k
    if n != 1:
        yield n, 1

上述代码注释:

  1. 我已经转换了这段代码,以便它生成分解,而不是构建一个列表(通过重复调用append)并返回它。在Python中,这种转换几乎总是一种改进,因为它允许您在生成元素时逐个使用它们,而不必将整个序列存储在内存中。

  2. 这是doctests效果良好的功能。

  3. 现在计算除数之和非常简单:不需要存储检查因子集或计算每个因子出现的次数。事实上,你可以只用一行:

    from operator import mul
    
    def sum_of_divisors(n):
        """
        Return the sum of divisors of n.
    
        >>> sum_of_divisors(1)
        1
        >>> sum_of_divisors(33550336) // 2
        33550336
        """
        return reduce(mul, ((p**(k+1)-1) // (p-1) for p, k in factorization(n)), 1)
    

答案 1 :(得分:1)

您只需更改两行:

def divisor_function(n):
    "Returns the sum of divisors of n"
    checked = {}
    factors = prime_factors(n)
    sum_of_divisors = 1 # It's = 1 because it will be the result of a product
    for x in factors:
        if checked.get(x,False):
            continue
        else:
            count = factors.count(x)
            tmp = (x**(count+1)-1)//(x-1)
            sum_of_divisors*=tmp
            checked[x]=True
    return sum_of_divisors

答案 2 :(得分:1)

为什么dictset - 或count() - ,当prime_factors()保证按升序返回因子时?您只处理之前的因素。计数只能是迭代的一部分:

def divisor_function(n):
    "Returns the sum of divisors of n"
    factors = prime_factors(n)
    sum_of_divisors = 1 
    count = 0; prev = 0;
    for x in factors:
        if x==prev:
            count += 1
        else:
            if prev: sum_of_divisors *= (prev**(count+1)-1)//(prev-1)
            count = 1; prev = x;
    if prev: sum_of_divisors *= (prev**(count+1)-1)//(prev-1)
    return sum_of_divisors

答案 3 :(得分:1)

def sum_divisors(n):
    assert n > 0
    if n == 1:
        return 0
    sum = 1
    if n % 2 == 0:              # if n is even there is a need to go over even numbers
        i = 2
        while i < sqrt (n):
            if n % i == 0:
                sum = sum + i + (n//i)  # if i|n then n/i is an integer so we want to add it as well
            i = i + 1
        if type (sqrt (n)) == int:  # if sqrt(n)|n we would like to avoid adding it twice
            sum = sum + sqrt (n)
    else:
        i = 3
        while i < sqrt (n):     # this loop will only go over odd numbers since 2 is not a factor
            if n % i == 0:
                sum = sum + i + (n//i)  # if i|n then n/i is an integer so we want to add it as well
            i = i + 2
        if type (sqrt (n)) == int:  # if sqrt(n)|n we would like to avoid adding it twice
            sum = sum + sqrt (n)
    return sum

答案 4 :(得分:0)

以下是我在Java数字实用程序(广泛用于Project Euler)中所做的事情:

  • 使用显式指数生成素数因子化(参见Gareth Rees的答案)。

  • 基于它展开各种功能中的素数因子分解。即,使用与素数因子分解相同的算法,但直接计算期望值而不是存储因子和指数。

  • 默认情况下,只测试除数为2和奇数的除数。我有方法firstDivisor(n)nextDivisor(n,d)

  • (可选)为绑定下的所有数字预先计算最小除数的表。如果您需要将所有或大多数数字分解到界限之下(通过大约sqrt(limit)提高速度),这非常有用。我将表格挂钩到firstDivisor(n)nextDivisor(n,d)方法中,因此这不会改变分解算法。