0

Below is my implementation of the Sieve of Eratosthenes to find prime numbers up to the upper limit parameter.

Currently, my code completes in around 2 seconds when my parameter is 2,000,000. I see that I'm making one extra step by setting the numbers to nil, and then compacting rather than just deleting those numbers in one step.

How would I go about implementing this? Do you also have any other suggestions to improve the speed of my code?

def sieve(upper)
  i = 0
  list = (2..upper).to_a

  (2..Math.sqrt(upper)).each do |mult|
    init = mult + i
    (init..upper-1).step(mult) do |index|
      list[index] = nil
    end
    i += 1
  end
  list.compact
end
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
jchi2241
  • 2,032
  • 1
  • 25
  • 49
  • Imperative code is faster (`while` loops) but less readable. – Victor Moroz Sep 25 '13 at 01:13
  • please see [this answer](http://stackoverflow.com/a/18349336/849891) about using [empirical orders of growth](http://en.wikipedia.org/wiki/Analysis_of_algorithms#Empirical_orders_of_growth) to assess run time efficiency of programs. One point measurement says nothing. Is it `~ n^2.0`? `~ n^1.1`? – Will Ness Sep 25 '13 at 11:16
  • You should probably ask this on [Code Review](http://codereview.stackexchange.com) instead of Stack Overflow. SO is for fixing broken stuff. CR is for improving working stuff. – the Tin Man Sep 25 '13 at 14:52
  • This is *not* Eratosthenes Sieve, which removes only the multiples of each *prime*, i.e. the next remaining number in the list. – Borodin Sep 26 '13 at 10:35
  • ok, [I measured it for you](http://ideone.com/GXkFhK) (and the code from the answer as well). :) – Will Ness Sep 26 '13 at 20:55

1 Answers1

1

You could skip the loop where mult is not a prime number.

def sieve(upper)
  i = 0
  list = (2..upper).to_a
  (2..Math.sqrt(upper)).each do |mult|
    if list[i] #proceed only when mult is prime
      init = mult + i
      (init..upper-1).step(mult) do |index|
        list[index] = nil
      end
    end
    i += 1
  end
  list.compact
end

This trims down the runtime from 1.9 to 0.7 secs on my machine. I'm sure there's a lot more that can be done, though.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Worakarn Isaratham
  • 1,034
  • 1
  • 9
  • 16
  • next improvement (though probably with less of an impact) is to start from mult^2, not from 2*mult. :) ... and skip over the evens a priori. – Will Ness Sep 26 '13 at 20:56