3

This is my code in python for calculation of sum of prime numbers less than a given number.
What more can I do to optimize it?

import math
primes = [2,]                      #primes store the prime numbers



for i in xrange(3,20000,2):                    #i is the test number
    x = math.sqrt(i)
    isprime = True
    for j in primes:               #j is the devider. only primes are used as deviders
        if j <= x:
            if i%j == 0:
                    isprime = False
                    break


    if isprime:
        primes.append(i,)


print sum (primes,)
tarashish
  • 1,945
  • 21
  • 32

5 Answers5

5

You can use a different algorithm called the Sieve of Eratosthenes which will be faster but take more memory. Keep an array of flags, signifying whether each number is a prime or not, and for each new prime set it to zero for all multiples of that prime.

N = 10000

# initialize an array of flags
is_prime = [1 for num in xrange(N)]
is_prime[0] = 0 # this is because indexing starts at zero
is_prime[1] = 0 # one is not a prime, but don't mark all of its multiples!

def set_prime(num):
    "num is a prime; set all of its multiples in is_prime to zero"
    for x in xrange(num*2, N, num):
        is_prime[x] = 0

# iterate over all integers up to N and update the is_prime array accordingly
for num in xrange(N):
    if is_prime[num] == 1:
        set_prime(num)

primes = [num for num in xrange(N) if is_prime[num]]

You can actually do this for pretty large N if you use an efficient bit array, such as in this example (scroll down on the page and you'll find a Sieve of Eratosthenes example).

taleinat
  • 8,441
  • 1
  • 30
  • 44
  • 2
    this is pretty nice and fast method i see..while i clearly understand the concept and the process i am a bit uncomfortable with the syntax..especially with the initialization line and the last line which forms the list of primes.. unfortunately i dont have any python book with me and i couldnt find the array of flags in the official docs.. could anyone provide me a link for some readings?? – tarashish Nov 06 '11 at 07:55
  • The array of flags in this example is just a list of numbers, where I put `1` if the number is prime and `0` otherwise. As for the syntax of those two lines, search for "list comprehension" to find documentation. In a few words, it is a compact way to write a simple loop which creates a list. – taleinat Nov 06 '11 at 10:24
4

Another thing you could optimize is move the sqrt computation outside the inner loop. After all, i stays constant through it, so there's no need to recompute sqrt(i) every time.

Eli Bendersky
  • 263,248
  • 89
  • 350
  • 412
3

primes = primes + (i,) is very expensive. It copies every element on every pass of the loop, converting your elegant dynamic programming solution into an O(N2) algorithm. Use lists instead:

primes = [2]
...
    primes.append(i)

Also, exit the loop early after passing sqrt(i). And, since you are guaranteed to pass sqrt(i) before running off the end of the list of primes, update the list in-place rather than storing isprime for later consumption:

...
if j > math.sqrt(i):
    primes.append(i)
    break
if i%j == 0:
    break
...

Finally, though this has nothing to do with performance, it is more Pythonic to use range instead of while:

for i in range(3, 10000, 2):
    ...
Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
  • 2
    It's O(n^2) anyway, but of course it's better to get rid of the tuples. Even faster than using `primes.append()` is to compute the sum on the fly and not store the primes at all. – Sven Marnach Nov 05 '11 at 10:10
  • 1
    If he's using python2.x, it would be better to use xrange, too. – Thomas Orozco Nov 05 '11 at 10:10
  • 1
    @Sven: if he doesn't store the primes, he's going to have a harder time doing the prime checks. – Thomas Orozco Nov 05 '11 at 10:13
  • 1
    @Thomas yes i am using python 2.7..i am not much familiar with xrange though..gonna look it up in the docs..and another thing ..should i always use list instead of tuples? and isnt there any way to add things to tuple? – tarashish Nov 05 '11 at 10:19
  • @unus sunu: A tuple is an immutable version of a list. You can't change it at all, though you can always make a new one with the change you want. – Tommy Herbert Nov 05 '11 at 10:23
  • Simple answer is: lists are mutable, tuples are not, so you can decide which to use based on that. This does mean you can't add things to a tuple. You could also look up sets if you want, they are more appropriate for your problem. – Thomas Orozco Nov 05 '11 at 10:23
  • @unussunu: Tuples are immutable in Python. Whenever you want a mutable collection, tuples are not an option. This doesn't mean you should always use lists instead of tuples. – Sven Marnach Nov 05 '11 at 10:24
  • Sometimes immutability is a good thing - for example, in the keys of a dictionary. – Tommy Herbert Nov 05 '11 at 10:25
  • @SvenMarnach: With lists instead of tuples, it's O(n^1.5), thanks to the square-root. – Marcelo Cantos Nov 05 '11 at 11:54
  • @Marcelo: Only if the loop really exits at the square-root, which neither the OP's original version of the code nor the edited version does. – Sven Marnach Nov 05 '11 at 13:25
  • @SvenMarnach: Yes, you're right. I was thinking in terms of the suggestion in my answer. – Marcelo Cantos Nov 05 '11 at 22:25
1

Just another code without using any imports:

#This will check n, if it is prime, it will return n, if not, it will return 0
def get_primes(n):
    if n < 2:
        return 0
    i = 2
    while True:
        if i * i > n:
            return n
        if n % i == 0:
            return 0
        i += 1

#this will sum up every prime number up to n
def sum_primes(n):
    if n < 2:
        return 0
    i, s = 2, 0
    while i < n:
        s += get_primes(i)
        i += 1
    return s

n = 1000000
print sum_primes(n)
Inbar Rose
  • 41,843
  • 24
  • 85
  • 131
0

EDIT: removed some silliness while under influence

All brute-force type algorithms for finding prime numbers, no matter how efficient, will become drastically expensive as the upper bound increases. A heuristic approach to testing for primeness can actually save a lot of computation. Established divisibility rules can eliminate most non-primes "at-a-glance".

shimofuri
  • 691
  • 2
  • 13
  • 27
  • This is a very bad idea. The linked page only shows that containment tests are faster for sets, and the above code does not use such a test. Most other operations are actually slower for sets. Most importantly, though, we would lose the order of the primes, so we could not exit the loop upon reaching the square root any more. – Sven Marnach Nov 05 '11 at 14:10