如何使以下python代码更有效地查找友好对

时间:2019-06-27 15:06:44

标签: python

我编写了一个python程序,该程序可以在特定范围内找到友好对。我认为有很多更好的方法可以做到这一点,并且正在寻找有关如何改进我的代码的反馈。

def d(n):
    x = []
    for i in range(1, n):
        if n % i == 0:
            x.append(i)
    return sum(x)

def amicable(z,y):
    if d(z) == y and d(y) == z:
        print(z, y) 

for z in range(0, 10000, 2):
    for y in range(0, 10000, 2):
        if z != y:
            amicable(z, y)

此代码实际上执行了应有的功能,但效率不高。我要等一会儿结果。

2 个答案:

答案 0 :(得分:0)

不幸的是,我的箱子里所有我的项目Euclid的东西都在存储中,所以我将为您模拟一些东西。有机会计算一些素数时,我将对此进行测试。

通常,查找数字除数的最佳方法是仅检查素数。另外,您只需要检查数字的平方根即可。另外,存储素数列表很方便,因为它们需要很长时间才能计算出来。

您还可以使用一些嵌套循环魔术来检查配对的一半。

这是一个通用方案:

def save_primes(primes):
    #save your primes file, they take a long time to compute
    pass
def load_primes(fname):
    #load your primes file
    ....
    return primes

def compute_primes(n):
    #get the prime numbers up to n
    primes = []
    ...
    save_primes(primes, "my_primes")

def get_prime_divisors(n):
    #return prime divisors and their multiplicity
    global PRIMES
    prime_divisors = []
    prime_divisor_multiplicities = []
    j = 0
    if "PRIMES" not in globals():
        PRIMES = load_primes("my_primes")
    while PRIMES[j] < n**0.5:
        prime = PRIMES[j]
        if n % prime == 0:                
            k = 0
            while n % prime == 0:
                n = n//prime
                k += 1
            prime_divisors.append(prime)
            prime_divisor_multiplicities.append(k)
    return prime_divisors, prime_divisor_multiplicities

def d(n):
    import itertools
    prime_divisors, multiplicities = get_prime_divisors(n)
    sum_divisors = 0
    for powers in itertools.product(map(range, multiplicities))):
        for i, prime in enumerate(prime_divisors):
            sum_divisors += prime**powers[i]
    sum_divisors -= n #only proper divisors
    return sum_divisors

def amicable(z,y):
    if d(z) == y and d(y) == z:
        return True
    return False

for z in range(0, 10000-1, 2):
    for y in range(z+1, 10000, 2):
        if amicable(z, y):
            print(z,y)

答案 1 :(得分:0)

我可以使用numpy来加快您的代码速度,并避免对同一对计算两次。

import numpy as np

def divisors_sum(n):
    x = np.arange(1, n)
    return np.sum(x[(n % x) == 0])

def is_amicable(z,y):
    if divisors_sum(z) == y and divisors_sum(y) == z:
        return True
    return False

def amicable_pairs(N):
    for z in range(0, N, 2):
        for y in range(z+2, N, 2):
            if is_amicable(z, y) is True:
                print(z,y)

如果我与您的代码进行比较

def d(n):
    x = []
    for i in range(1, n):
        if n % i == 0:
            x.append(i)
    return sum(x)


def is_amicable_old(z,y):
    if d(z) == y and d(y) == z:
        return True
    return False

def amicable_pairs_old(N):
    for z in range(0, N, 2):
        for y in range(0, N, 2):
            if z!=y:
                if is_amicable_old(z, y) is True:
                    print(z, y)

我知道了

%%time
amicable_pairs(1000)

220 284
CPU times: user 1.69 s, sys: 28 ms, total: 1.72 s
Wall time: 1.69 s

同时

%%time
amicable_pairs_old(1000)

220 284
284 220
CPU times: user 7.35 s, sys: 7.85 ms, total: 7.35 s
Wall time: 7.35 s