如何在代码中实现除数函数?

时间:2012-01-31 08:12:54

标签: python

总体问题:项目Euler 12 - 第一个三角形数值超过500个除数的值是多少?

问题的焦点:除数函数

语言:Python

描述:我使用的函数是粗暴的,程序找到一个除数比x多的数字所需的时间几乎呈指数增长,每10或20个数字更高。我需要达到500或更多的除数。我已经确定了除数函数正在减少程序。我做的研究引导我去除除数函数,特别是 除数函数,它应该是一个函数,它将计算任何整数的所有除数。我看过的每一页似乎都是针对数学专业的,我只有高中数学。虽然我确实遇到过一些关于素数和阿特金斯筛选的页面,但是我无法在素数之间建立连接并找到任何整数的所有除数,也没有在网上找到关于它的任何东西。

主要问题有人可以解释如何编码除数函数甚至提供样本吗?当我用代码查看它们时,数学概念对我来说更有意义。非常感谢。

强力除数函数:

def countdiv(a):
    count = 0
    for i in range(1,(a/2)+1):
        if a % i == 0:
            count += 1
    return count + 1    # +1 to account for number itself as a divisor

4 个答案:

答案 0 :(得分:5)

如果你需要一个暴力函数来计算除数(也称为tau(n))

这就是它的样子

def tau(n):
        sqroot,t = int(n**0.5),0
        for factor in range(1,sqroot+1):
                if n % factor == 0:
                        t += 2 # both factor and N/factor
        if sqroot*sqroot == n: t = t - 1 # if sqroot is a factor then we counted it twice, so subtract 1
        return t

第二种方法涉及将n分解为其主要因子(及其指数)。

tau(n) = (e1+1)(e2+1)....(em+1)其中n = p1^e1 * p2^e2 .... pm^emp1,p2..pm are primes

更多信息here

第三种方法更容易理解,只需使用Sieve来计算tau

def sieve(N):
        t = [0]*(N+1)
        for factor in range(1,N+1):
                for multiple in range(factor,N+1,factor):
                        t[multiple]+=1
        return t[1:]

这是ideone

的实际操作

答案 1 :(得分:4)

我同意此处提交的其他两个答案,您只需要搜索该号码的平方根。不过,我有一件事要补充一点。提供的解决方案将在合理的时间内为您提供正确的答案。但是当问题变得越来越困难时,你将需要一个更强大的功能。

看看Euler's Totient function。虽然它只是间接适用于此,但它在后来的问题中非常有用。另一个相关概念是Prime Factorization

改进算法的一种快速方法是找到数字的素数因子分解。在维基百科文章中,他们使用36作为示例,其素数因子分解为2 ^ 2 * 3 ^ 2。因此,知道这一点,你可以使用组合数来找出36的因子数。这样,​​你实际上不会计算每个因子,而且你只需要在完成之前检查除数2和3。

答案 2 :(得分:1)

在搜索n的除数时,您永远不必搜索数字n平方根。每当你发现一个小于sqrt(n)的除数时,只有一个匹配除数大于根,所以你可以将count增加2(如果你找到除数d { {1}}然后n将成为对应方。)

注意方形数字。 :)当然,根将是一个不计数两次的除数。

答案 3 :(得分:0)

如果你要解决Project Euler问题,你需要一些处理素数和整数分解的函数。这是我的适度库,提供primes(n)is_prime(n)factors(n);重点是简单,清晰和简洁而牺牲速度,尽管这些功能应该足以让Project Euler:

def primes(n):
    """
        list of primes not exceeding n in ascending
        order; assumes n is an integer greater than
        1; uses Sieve of Eratosthenes
    """
    m = (n-1) // 2
    b = [True] * m
    i, p, ps = 0, 3, [2]
    while p*p < n:
        if b[i]:
            ps.append(p)
            j = 2*i*i + 6*i + 3
            while j < m:
                b[j] = False
                j = j + 2*i + 3
        i += 1; p += 2
    while i < m:
        if b[i]:
            ps.append(p)
        i += 1; p += 2
    return ps

def is_prime(n):
    """
        False if n is provably composite, else
        True if n is probably prime; assumes n
        is an integer greater than 1; uses
        Miller-Rabin test on prime bases < 100
    """
    ps = [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 is_spsp(n, a):
        d, s = n-1, 0
        while d%2 == 0:
            d /= 2; s += 1
        if pow(a,d,n) == 1:
            return True
        for r in xrange(s):
            if pow(a, d*pow(2,r), n) == n-1:
                return True
        return False
    if n in ps: return True
    for p in ps:
        if not is_spsp(n,p):
            return False
    return True

def factors(n):
    """
        list of prime factors of n in ascending
        order; assumes n is an integer, may be
        positive, zero or negative; uses Pollard's
        rho algorithm with Floyd's cycle finder
    """
    def gcd(a,b):
        while b: a, b = b, a%b
        return abs(a)
    def facts(n,c,fs):
        f = lambda(x): (x*x+c) % n
        if is_prime(n): return fs+[n]
        t, h, d = 2, 2, 1
        while d == 1:
            t = f(t); h = f(f(h))
            d = gcd(t-h, n)
        if d == n:
            return facts(n, c+1, fs)
        if is_prime(d):
            return facts(n//d, c+1, fs+[d])
        return facts(n, c+1, fs)
    if -1 <= n <= 1: return [n]
    if n < -1: return [-1] + factors(-n)
    fs = []
    while n%2 == 0:
        n = n//2; fs = fs+[2]
    if n == 1: return fs
    return sorted(facts(n,1,fs))

一旦你知道如何计算一个数字,就很容易计算除数的数量。考虑76576500 = 2 ^ 2 * 3 ^ 2 * 5 ^ 3 * 7 ^ 1 * 11 ^ 1 * 13 ^ 1 * 17 ^ 1。忽略基数并查看指数,即2,2,3,1,1,1和1.为每个指数加1,给出3,3,4,2,2,2和2.现在相乘该列表获取原始数字76576500的除数数:3 * 3 * 4 * 2 * 2 * 2 * 2 = 576.这是函数:

def numdiv(n):
    fs = factors(n)
    f = fs.pop(0); d = 1; x = 2
    while fs:
        if f == fs[0]:
            x += 1
        else:
            d *= x; x = 2
        f = fs.pop(0)
    return d * x

您可以在http://codepad.org/4j8qp60u处查看这些功能,并详细了解它们在my blog的工作原理。我会留给你解决问题12的解决方案。