哥德巴赫猜想 - 找出偶数可以写成两个素数之和的方式

时间:2016-12-31 18:14:58

标签: python math

我想知道给定正数偶数的方式可以写成两个素数的总和。

目前,我有这段代码:

n = int(input(">"))
def genprimes(n):#generate primes from 2 to n
    primes = []
    for i in range(2,n):
        prime = True
        for a in range(2,i):
            if i % a == 0:
                prime = False
        if prime == True:
            primes.append(i)
    return primes

pairs = []
primes = genprimes(n)

for prime1 in primes:
    for prime2 in primes:
        if prime1 + prime2 == n and [prime1,prime2] not in pairs and [prime2,prime1] not in pairs:
            pairs.append([prime1,prime2])
print(len(pairs))

它有效,但当n超过10,000时,它会变得有点慢。任何人都可以想到一种更有效的方法来找到这个值,这样它可以为高值产生快速结果吗?

5 个答案:

答案 0 :(得分:4)

你有两种慢速算法。

要获取素数列表,请分别检查每个号码是否为素数据。获得素数列表的最快方法是使用预先建立的素数列表 - 这就是我为这些问题所做的。最多2 ** 16(65,536)的素数列表只需要6542个整数,我将该列表存储在一个模块中。您可能更喜欢使用Sieve of Eratosthenes,这通常被认为是从头开始获取此类列表的最快方式。

然后尝试每对素数以查看它们是否添加到目标数字。对于每个素数p,查看n-p是否也是素数会快得多。您可以使用二进制搜索来检查n-p,正如@Shubham建议的那样,但是有两个索引可能会更快,一个经常上升并产生p而另一个下降需要检查{ {1}}。将您的主要列表复制到集合可能是最快的,并使用它来检查列表中是否n-p。最后两种技术的顺序为n-p,但对于仅高达10,000的数字,开销可能会影响哪种技术最佳。是的,对于这些问题,10,000不是很大。最后,如果内存不是问题,@ BondKeith指出你可以将主要列表作为布尔值列表(真/假)并且非常快速地检查n是否为素数 - 这是最快的,如果最耗费内存的技术。

答案 1 :(得分:2)

这可以通过优化程序的两个部分来有效地完成。

首先,我们可以通过使用Sieve of Eratosthenes生成素数来优化genprimes(),这可以在n中生成素数O(nlog(log(n))

之后,一旦我们有了素数列表,我们就可以做到以下几点:

  • 遍历主要列表并选择一个素数,例如p1
  • 使用二进制搜索检查主要列表中是否还存在n-p1

如果p = number of primes till n

然后这部分的复杂性将是O(plog(p))

正如@PaulHankin建议的那样,根据@SrujanKumarGulla的回答,我们可以在获得主要列表后构建O(p)解决方案。

第二部分的实施(第一部分是标准Sieve of Eratosthenes):

# prime list is assumed to be sorted. It will be if it's generated
# using Sieve of Eratosthenes

def solutions(n, prime_list):
    low = 0, high = len(prime_list)-1
    sol = []
    while low < high:
        temp = prime_list[low] + prime_list[high]
        if temp == n:
            sol.append((prime_list[low], prime_list[high], ))
        elif temp < n:
            low += 1
        else:
            high -= 1

    return len(sol)

答案 2 :(得分:1)

如果内存不是问题,您可以通过以下方式进一步优化速度:

1)如果i是素数,则从2..n构建数组,其中array [i] = true。 (可以使用Eratosthenes的Sieve或者更高级的东西。)

2)对于所有2&lt; = i&lt; n / 2看看array [i]和array [n-i]是否都为真。如果是这样,那么我和n-i是一对。 (将i的上限设置为n / 2意味着您不必删除重复项。)

整个算法是O(n log n)。 (O(n log n)构建素数; O(n)求构。)

我是用C#而不是Python做的,但能够在10秒内找到n = 100,000,000的所有对。

答案 3 :(得分:1)

    def prim(n):
        primes = []
        for num in range(1, n + 1):     # current number check
            limit = int(num ** 0.5) + 1 # search limit
            for div in range(2, limit): # searching for divider
                if (num % div) == 0:    # divider found
                    break               # exit the inner loop
            else:                       # out of the inner loop
                primes.append(num)      # no divider found hence prime
        return(primes)

    num = int(input('Input an even number: '))
    primes = prim(num)                  # create list of primes

    for i in range(num//2 + 1):
        if num % 2 != 0:
            print(num, 'not even'); break
        if i in primes and (num - i) in primes:
            print(i, '+', num - i)
"""
Examples:
=========
Input an even number: 18
1 + 17
5 + 13
7 + 11

Input an even number: 88
5 + 83
17 + 71
29 + 59
41 + 47

Input an even number: 17
17 not even
"""

答案 4 :(得分:0)

这是来自Rory建议的实际解决方案,它使用Eratosthenes的Sieve来有效地生成素数,然后看n-prime是否也是素数。

然后需要将解决方案的计数减半并四舍五入以防止重复。

n = int(input(">"))
def genprimes(n):
    limitn = n+1
    not_prime = set()
    primes = []

    for i in range(2, limitn):
        if i in not_prime:
            continue
        for f in range(i*2, limitn, i):
            not_prime.add(f)
        primes.append(i)
    return primes

nos=0
primes = genprimes(n)

for prime in primes:
    if n-prime in primes:
        nos += 1
print(str(int((nos/2)+0.5)))