如何在Python中生成此列表?
a(n)的形式不是素数+ a(k),k 以下是oeis http://oeis.org/A025043 分别为0、1、9、10、25、34、35、49、55、85、91、100、115、121。 我尝试了大胆的方式,但效果不佳。现在,我正在寻找一种复杂的解决方案,例如Eratosthenes的Sieve作为素料。
大胆的方法要求迭代每个素数,并且对于素数的每次迭代,都迭代序列中已经存在的每个数字,这需要很长时间。 该表由聪明的人生成:http://oeis.org/A025043/b025043.txt
他们要么使用大量计算能力,要么使用我正在寻找的复杂算法。 为解释此序列是什么,可以将序列中不存在的每个数字表示为该序列中质数和数字的总和。例如8 = 7(素数)+ 1(顺序),54 = 53(素数)+1(顺序),等等。
答案 0 :(得分:7)
生成此序列的明显方法是生成所有素数,然后使用筛子。对于找到的序列中的每个新元素x
,在所需范围内删除所有素数x+p
的{{1}}。
mathoverflow注释猜测该序列的密度趋于N / sqrt(ln N)。如果正确,那么此代码将在时间O(N ^ 2 /(ln N)^ 3/2)中运行。 (使用小于N的素数数约为N / ln N)。
一旦N达到10 ^ 6,这将非常慢,但是在我的桌面上运行代码表明即使N = 10 ^ 7,您也将在几小时内获得完整列表。请注意,该算法变得越来越快,因此不要因初始缓慢而过分推迟。
Python 3代码:
p
用C重新编写它,并使用import array
N = 10000
def gen_primes(N):
a = array.array('b', [0] * (N+1))
for i in range(2, N+1):
if a[i]: continue
yield i
for j in range(i, N+1, i):
a[j] = 1
def seq(N):
primes = list(gen_primes(N))
a = array.array('b', [0] * (N+1))
for i in range(N+1):
if a[i]: continue
yield i
for p in primes:
if i + p > N:
break
a[i+p] = 1
for i in seq(N):
print(i, end=' ', flush=True)
print()
进行编译可以提供更快的解决方案。这段代码会在我的计算机上的7分30秒内生成最多10 ^ 7的列表:
gcc -O2
答案 1 :(得分:3)
Eratosthenes的筛子看起来与素数筛子非常相似。但是您需要从素数列表开始。
使用质数时,您有一堆i * prime(k)
项,其中prime
是我们的序列,i
是序列中每个元素的增加量。
这里有一堆prime(i) + a(k)
项,其中a
是我们的序列,i
是我们为序列中每个元素增加的量。
当然,+
而不是*
在整体效率上有很大的不同。
下面的代码在几秒钟内达到100k,因此如果要生成特别大的数字,它将变得很慢。
您可以等待,看看是否有人想出一种更快的方法。
# taken from https://stackoverflow.com/questions/3939660
def primes_sieve(limit):
a = [True] * limit
a[0] = a[1] = False
for (i, isprime) in enumerate(a):
if isprime:
yield i
for n in range(i*i, limit, i):
a[n] = False
def a_sieve(limit, primes):
a = [True] * limit
for (i, in_seq) in enumerate(a):
if in_seq:
yield i
for n in primes:
if i+n >= limit:
break
a[i+n] = False
primes = list(primes_sieve(100000))
a = list(a_sieve(100000, primes))
# a = [0, 1, 9, 10, 25, 34, 35, 49, 55, 85, 91, 100, 115, 121, 125, 133, 145, ...]
为了进行比较,我编写了下面的蛮力方法,一种方法迭代素数并检查是否减法给出了序列中的元素,另一种方法迭代了素数并检查我们是否得到素数,这两种方法都需要大约是100k的两倍。
它看起来确实与Sieve相似,但是它向后看而不是向前设置值。
def a_brute(limit, primes):
a = [True] * limit
for i in range(limit):
for p in primes:
if i-p < 0:
yield i
break
if a[i-p]:
a[i] = False
break
else:
yield i
def a_brute2(limit, primes_sieve):
a = [True] * limit
l = []
for i in range(limit):
for j in l:
if i-j < 0:
l.append(i)
break
if primes_sieve[i-j]:
a[i] = False
break
else:
l.append(i)
return l
结果:
Primes sieve: 0.02 seconds
Sieve: 6.26 seconds
Brute force 1: 14.14 seconds
Brute force 2: 12.34 seconds