Optimización de la función de búsqueda de números primos

After 10 minutes of work I have written a function presented below. It returns a list of all primes lower than an argument. I have used all known for me programing and mathematical tricks in order to make this function as fast as possible. To find all the primes lower than a million it takes about 2 seconds.

Do you see any possibilities to optimize it even further? Any ideas?

def Primes(To):
  if To<2:
    return []
  if To<3:
    return [2]
  Found=[2]
  n=3
  LastSqr=0
  while n<=To:
     k=0
     Limit=len(Found)
     IsPrime=True
     while k<Limit:
         if k>=LastSqr: 
            if Found[k]>pow(n,0.5): 
               LastSqr=k
               break
         if n%Found[k]==0:
            IsPrime=False
            break
         k+=1
     if IsPrime:
        Found.append(n)
     n+=1
  return Found

preguntado el 31 de julio de 12 a las 14:07

Yo adivinaría que sqrt(n) es más rápido que pow(n,0.5) -

A quick test with timeit confirms, sqrt(n) es de hecho más rápido que pow(n,0.5) -

@user1354439 Please have a look at PEP 8 concerning the names of identifiers such as local variables. -

3 Respuestas

You can use a couple tricks to speed things up, using the basic sieve of erastothenes. One is to use Wheel Factorization to skip calculating numbers that are known not to be prime. For example, besides 2 and 3, all primes are congruent to 1 or 5 mod 6. This means you don't have to process 4 of every 6 numbers at all.

At the next level, all primes are congruent to 1, 7, 11, 13, 17, 19, 23, or 29, mod 30. You can throw out 22 of every 30 numbers.

Here is a simple implementation of the sieve of Erastothenes that doesn't calculate or store even numbers:

def basic_gen_primes(n):
    """Return a list of all primes less then or equal to n"""
    if n < 2:
        return []

    # The sieve.  Each entry i represents (2i + 1)
    size = (n + 1) // 2
    sieve = [True] * size

    # 2(0) + 1 == 1 is not prime
    sieve[0] = False

    for i, value in enumerate(sieve):
        if not value:
            continue

        p = 2*i + 1

        # p is prime.  Remove all of its multiples from the sieve
        # p^2 == (2i + 1)(2i + 1) == (4i^2 + 4i + 1) == 2(2i^2 + 2i) + 1
        multiple = 2 * i * i + 2 * i 
        if multiple >= size:
            break

        while multiple < size:
            sieve[multiple] = False
            multiple += p 

    return [2] + [2*i+1 for i, value in enumerate(sieve) if value]

As mentioned, you can use more exotic sieves as well.

Respondido 03 ago 12, 14:08

2 * i * i + 2 * i == 2 * i * (i + 1). - Will Ness

the fact deserves destacando that your code here is the tamiz de Eratóstenes, and so should always be much faster than a trial division code like that of OP, when implemented correctly. - Will Ness

You can check only odd numbers. So why don't you use n+=2 instead of n+=1?

Respondido 31 Jul 12, 14:07

Good idea :) I will check if it has shortened the time of execution, Thank you - Piotr Dabkowski

Incrementing by six and checking n-1 y n+1 in each iteration might be faster still. It's a common trick to optimize the Sieve of Eratosthenes by skipping over the multiples of three as well. (Never tried it in Python, though.) - fred foo

google and wikipedia for better algorithms. If you are only looking for small primes this might be fast enough. But the real algorithms are a lot faster for large primes.

http://en.wikipedia.org/wiki/Quadratic_sieve

start with that page.

Increment n by two instead of one. ?

Respondido 31 Jul 12, 14:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.