I’m doing problems from Project Euler in Ruby and implemented Atkin’s sieve for finding prime numbers but it runs slower than sieve of Eratosthenes. What is the problem?
def atkin_sieve(n)
primes = [2,3,5]
sieve = Array.new(n+1, false)
y_upper = n-4 > 0 ? Math.sqrt(n-4).truncate : 1
for x in (1..Math.sqrt(n/4).truncate)
for y in (1..y_upper)
k = 4*x**2 + y**2
sieve[k] = !sieve[k] if k%12 == 1 or k%12 == 5
end
end
y_upper = n-3 > 0 ? Math.sqrt(n-3).truncate : 1
for x in (1..Math.sqrt(n/3).truncate)
for y in (1..y_upper)
k = 3*x**2 + y**2
sieve[k] = !sieve[k] if k%12 == 7
end
end
for x in (1..Math.sqrt(n).truncate)
for y in (1..x)
k = 3*x**2 - y**2
if k < n and k%12 == 11
sieve[k] = !sieve[k]
end
end
end
for j in (5...n)
if sieve[j]
prime = true
for i in (0...primes.length)
if j % (primes[i]**2) == 0
prime = false
break
end
end
primes << j if prime
end
end
primes
end
def erato_sieve(n)
primes = []
for i in (2..n)
if primes.all?{|x| i % x != 0}
primes << i
end
end
primes
end
As Wikipedia says, “The modern sieve of Atkin is more complicated, but faster when properly optimized” (my emphasis).
The first obvious place to save some time in the first set of loops would be to stop iterating over
ywhen4*x**2 + y**2is greater thann. For example, ifnis 1,000,000 andxis 450, then you should stop iterating whenyis greater than 435 (instead of continuing to 999 as you do at the moment). So you could rewrite the first loop as:(This also avoids re-computing
4*x**2each time round the loop, though that is probably a very small improvement, if any.)Similar remarks apply, of course, to the other loops over
y.A second place where you could speed things up is in the strategy for looping over
y. You loop over all values ofyin the range, and then check to see which ones lead to values ofkwith the correct remainders modulo 12. Instead, you could just loop over the right values ofyonly, and avoid testing the remainders altogether.If
4*x**2is 4 modulo 12, theny**2must be 1 or 9 modulo 12, and soymust be 1, 3, 5, 7, or 11 modulo 12. If4*x**2is 8 modulo 12, theny**2must be 5 or 9 modulo 12, soymust be 3 or 9 modulo 12. And finally, if4*x**2is 0 modulo 12, theny**2must be 1 or 5 modulo 12, soymust be 1, 5, 7, 9, or 11 modulo 12.I also note that your sieve of Eratosthenes is doing useless work by testing divisibility by all primes below
i. You can halt the iteration once you’ve test for divisibility by all primes less than or equal to the square root ofi.