简体   繁体   English

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

[英]How do you implement the divisor function in code?

Overall Problem: Project Euler 12 - What is the value of the first triangle number to have over five hundred divisors? 总体问题:欧拉计画12-第一个三角数超过500的除数的值是多少?

Focus of problem: The divisor function 问题重点:除数功能

Language: Python 语言:Python

Description: The function I used is brute and the time it take for the program to find a number with more divisors than x increases almost exponentially with each 10 or 20 numbers highers. 说明:我使用的函数很残酷,并且程序找到一个比x多的数所花费的时间几乎每增加10或20个数就成指数增长。 I need to get to 500 or more divisors. 我需要达到500个或更多除数。 I've identified that the divisor function is what is hogging down the program. 我已经确定除数功能正在拖累程序。 The research I did lead me to divisor functions and specifically the divisor function which is supposed to be a function that will count all the divisors of any integer. 我所做的研究使我了解了除数函数,尤其除数函数, 函数应该是可以计算任何整数的所有除数的函数。 Every page I've looked at seems to be directed toward mathematics majors and I only have high-school maths. 我浏览的每一页似乎都是针对数学专业的,而我只有高中数学。 Although I did come across some page that mentioned allot about primes and the Sieve of Atkins but I could not make the connection between primes and finding all the divisors of any integer nor find anything on the net about it. 尽管我确实碰到过一些提到素数和阿特金斯筛分法的页面,但是我无法建立素数之间的联系,也找不到任何整数的所有除数,也无法在网上找到任何关于它的因数。

Main Question : Could someone explain how to code the divisor function or even provide a sample ? 主要问题有人可以解释如何编写除数函数,甚至提供示例吗? Maths concepts make more sense to me when I look at them with code. 当我用代码查看数学概念时,对我来说更有意义。 So much appreciated. 非常感谢。

brute force divisor function: 蛮力除数函数:

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

If you need a bruteforce function to calculate Number of Divisors (also known as tau(n)) 如果您需要蛮力函数来计算除数(也称为tau(n))

Here's what it looks like 这是它的样子

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

The second method involves a decomposing n into its prime factors (and its exponents). 第二种方法涉及将n分解为其素数因子(及其指数)。

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

More info here 更多信息在这里

The third method and much more simpler to understand is simply using a Sieve to calculate tau . 第三种方法(更容易理解)只是使用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:]

Here's it in action at ideone 这是ideone的实际应用

I agree with the two other answers submitted here in that you will only need to search up to the square root of the number. 我同意这里提交的其他两个答案,因为您只需要搜索数字的平方根即可。 I have one thing to add to this however. 但是,我要添加一件事。 The solutions offered will get you the correct answer in a reasonable amount of time. 提供的解决方案将在合理的时间内为您提供正确的答案。 But when the problems start getting tougher, you will need an even more powerful function. 但是,当问题开始变得更加棘手时,您将需要更强大的功能。

Take a look at Euler's Totient function . 看一下Euler的Totient函数 Though it only indirectly applies here, it is incredibly useful in later problems. 尽管它仅间接适用于此,但在以后的问题中非常有用。 Another related concept is that of Prime Factorization . 另一个相关的概念是素因数分解

A quick way to improve your algorithm is to find the prime factorization of the number. 改进算法的一种快速方法是找到数字的素因式分解。 In the Wikipedia article, they use 36 as an example, whose prime factorization is 2^2 * 3^2. 在Wikipedia文章中,他们以36为例,其素数分解为2 ^ 2 * 3 ^ 2。 Therefore, knowing this, you can use combinatorics to find the number of factors of 36. With this, you will not actually be computing each factor, plus you'd only have to check divisors 2 and 3 before you're complete. 因此,知道了这一点,您便可以使用组合运算法来找到36个因数。这样一来,您实际上就不会计算每个因数,而且您只需要在完成除数后检查2和3的除数即可。

When searching for divisors of n you never have to search beyond the square root of the number n . 当搜索n除数时,您不必搜索数字n 平方根 Whenever you find a divisor that's less than sqrt(n) there is exactly one matching divisor which is greater than the root, so you can increment your count by 2 (if you find divisor d of n then n/d will be the counterpart). 每当发现除数小于sqrt(n)除数时,就会有一个匹配的除数正好大于根,因此可以将count加2(如果找到n除数d ,则n/d将为对数) 。

Watch out for square numbers, though. 但是请注意平方数。 :) The root will be a divisor that doesn't count twice, of course. :)根当然是除数不等于两次的除数。

If you're going to solve the Project Euler problems you need some functions that deal with prime numbers and integer factorization. 如果要解决Project Euler问题,则需要一些处理素数和整数分解的函数。 Here is my modest library, which provides primes(n) , is_prime(n) and factors(n) ; 这是我的谦虚库,提供了primes(n)is_prime(n)factors(n) the focus is on simplicity, clarity and brevity at the expense of speed, though these functions should be sufficient for 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))

Once you know how to factor a number, it is easy to count the number of divisors. 一旦知道如何分解数字,就很容易计算除数的数量。 Consider 76576500 = 2^2 * 3^2 * 5^3 * 7^1 * 11^1 * 13^1 * 17^1. 考虑76576500 = 2 ^ 2 * 3 ^ 2 * 5 ^ 3 * 7 ^ 1 * 11 ^ 1 * 13 ^ 1 * 17 ^ 1。 Ignore the bases and look at the exponents, which are 2, 2, 3, 1, 1, 1, and 1. Add 1 to each exponent, giving 3, 3, 4, 2, 2, 2, and 2. Now multiply that list to get the number of divisors of the original number 76576500: 3 * 3 * 4 * 2 * 2 * 2 * 2 = 576. Here's the function: 忽略底数,看一下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

You can see these functions at work at http://codepad.org/4j8qp60u , and learn more about how they work at my blog . 您可以在http://codepad.org/4j8qp60u上查看这些功能的工作原理,并在我的博客上了解有关它们如何工作的更多信息。 I'll leave it to you to work out the solution to Problem 12. 我将留给您解决问题12的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM