如果您不需要产生实际的素数,而只测试是否存在一对素数 p 和 q 使得 p+q == N,您可以根据哥德巴赫猜想将其变得非常简单。所有偶数都可以表示为两个素数之和。因此,如果数字是偶数,则返回 True 并检查 N-2 是否是奇数的素数(因为 2 是唯一的偶素数,这是从奇数开始时会产生另一个奇数的唯一素数)。这将归结为仅对奇数进行 N-2 的单个素数测试。
def primePart(N):
return N%2==0 or all((N-2)%p for p in range(3,int(N**0.5)+1,2))
primePart(3432) # True
primePart(37+2) # True
primePart(13+41) # True
primePart(123) # False
如果您想实际找到一对加起来为 N 的素数,您可以生成最多为 N 的素数并返回第一个素数 >= N/2 其中 N - 素数是已经找到的素数之一:
def findPQ(N):
if not primePart(N): return
if N%2: return 2,N-2
isPrime = [0]+[1]*N
for p in range(3,N,2):
if not isPrime[p]: continue
if 2*p>=N and isPrime[N-p]: return p,N-p
isPrime[p*p::p] = [0]*len(isPrime[p*p::p])
输出:
findPQ(3432) # (1723, 1709)
findPQ(12345678) # (6172879, 6172799)
要超过 10^9,您将需要一个内存效率更高的算法,而不是同样快的 Eratosthenes 筛子。这可以通过要跳过的素数倍数字典来实现:
def findPQ(N):
if not primePart(N): return
if N%2: return 2,N-2
skip,primes = {},{2}
for p in range(3,N,2):
if p in skip:
prime = skip.pop(p)
mult = p + 2*prime
while mult in skip: mult += 2*prime
if mult <= N: skip[mult] = prime
else:
if 2*p>=N and N-p in primes: return p,N-p
if p*p<=N: skip[p*p]=p
if 2*p<=N: primes.add(p)
输出(需要一段时间,但不会破坏内存空间):
findPQ(1234567890) # (617283983, 617283907)