The Sieve of Eratosthenes is going to look very similar to the one for primes. But you'll need to start off with a list of primes.
With primes you have a bunch of i * prime(k)
terms, where prime
is our sequence, and i
is what we increase for each element in the sequence.
Here you have a bunch of prime(i) + a(k)
terms, where a
is our sequence and i
is what we increase for each element in the sequence.
Of course the +
instead of *
makes a big difference in the overall efficiency.
The below code gets up to 100k in a few seconds, so it's going to be slow if you want to generate particularly large numbers.
You can wait and see if someone comes up with a faster method.
# 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, ...]
For comparison, I wrote the below brute force methods, one which iterates over primes and checks if subtracting that gives an element in our sequence, and another which iterates over our sequence and checks if we get a prime, both of which takes about twice as long for 100k.
It does look somewhat similar to the Sieve, but it looks backwards instead of setting values forwards.
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
Result:
Primes sieve: 0.02 seconds
Sieve: 6.26 seconds
Brute force 1: 14.14 seconds
Brute force 2: 12.34 seconds