N altındaki tüm primerleri listelemenin en hızlı yolu


358

Bu, gelebileceğim en iyi algoritma.

def get_primes(n):
    numbers = set(range(n, 1, -1))
    primes = []
    while numbers:
        p = numbers.pop()
        primes.append(p)
        numbers.difference_update(set(range(p*2, n+1, p)))
    return primes

>>> timeit.Timer(stmt='get_primes.get_primes(1000000)', setup='import   get_primes').timeit(1)
1.1499958793645562

Daha da hızlı hale getirilebilir mi?

Bu kodun bir kusuru vardır: numbersSırasız bir küme olduğundan, kümeden numbers.pop()en düşük sayıyı kaldıracağının garantisi yoktur . Bununla birlikte, bazı giriş numaraları için (en azından benim için) çalışır:

>>> sum(get_primes(2000000))
142913828922L
#That's the correct sum of all numbers below 2 million
>>> 529 in get_primes(1000)
False
>>> 529 in get_primes(530)
True

Sayılar = set (aralık (n, 2, -2)) gibi bildirilen sayılar söz konusu kod sniplet'i çok daha hızlıdır. Ama sundaram'ı yenemez3. Soru için teşekkürler.
Shekhar

3
Cevaplarda fonksiyonların Python 3 sürümleri olsa iyi olurdu.
Michael Foukarakis

Elbette bunu yapmak için bir kütüphane var, bu yüzden kendi> xkcd vaat edilen Python'un kadar basit olduğunu söylemek zorunda değiliz import antigravity. require 'prime'; Prime.take(10)(Ruby) gibi bir şey yok mu?
Albay Panik

2
@ColonelPanic Bu şekilde Py3 için github.com/jaredks/pyprimesieve'yi güncelledim ve PyPi'ye ekledim. Kesinlikle bunlardan daha hızlı ama büyüklük sıraları değil - en iyi numpy versiyonlarından ~ 5 kat daha hızlı.
Jared

3
@ColonelPanic: Bence, yaşlandıklarını belirtmek için eski cevapları düzenlemek uygun, çünkü bu onu daha kullanışlı bir kaynak yapıyor. "Kabul edilen" yanıt artık en iyisi değilse, 2015 güncellemesiyle soruya bir notu düzenleyin ve kullanıcıları mevcut en iyi yönteme yönlendirin.
Peter Cordes

Yanıtlar:


366

Uyarı: timeit Python'un donanım veya sürümündeki farklılıklar nedeniyle sonuçlar değişebilir.

Aşağıda bir dizi uygulamayı karşılaştıran bir betik bulunmaktadır:

Çok teşekkürler için stephan dikkatimi sieve_wheel_30 getirmek için. Primesfrom2to, primesfrom3to, rwh_primes, rwh_primes1 ve rwh_primes2 için Robert William Hanks'a kredi verildi.

N = 1000000 için psyco ile test edilen düz Python yöntemlerinden rwh_primes1 en hızlı test edildi.

+---------------------+-------+
| Method              | ms    |
+---------------------+-------+
| rwh_primes1         | 43.0  |
| sieveOfAtkin        | 46.4  |
| rwh_primes          | 57.4  |
| sieve_wheel_30      | 63.0  |
| rwh_primes2         | 67.8  |    
| sieveOfEratosthenes | 147.0 |
| ambi_sieve_plain    | 152.0 |
| sundaram3           | 194.0 |
+---------------------+-------+

Test düz Python yöntemlerin psyco olmadan n = 1000000 için, rwh_primes2 hızlı oldu.

+---------------------+-------+
| Method              | ms    |
+---------------------+-------+
| rwh_primes2         | 68.1  |
| rwh_primes1         | 93.7  |
| rwh_primes          | 94.6  |
| sieve_wheel_30      | 97.4  |
| sieveOfEratosthenes | 178.0 |
| ambi_sieve_plain    | 286.0 |
| sieveOfAtkin        | 314.0 |
| sundaram3           | 416.0 |
+---------------------+-------+

N = 1000000 için numpy'ye izin verilen test edilen tüm yöntemlerden primesfrom2to en hızlı test edildi.

+---------------------+-------+
| Method              | ms    |
+---------------------+-------+
| primesfrom2to       | 15.9  |
| primesfrom3to       | 18.4  |
| ambi_sieve          | 29.3  |
+---------------------+-------+

Zamanlamalar şu komut kullanılarak ölçüldü:

python -mtimeit -s"import primes" "primes.{method}(1000000)"

ile {method}yöntem adlarının her yerini almıştır.

primes.py:

#!/usr/bin/env python
import psyco; psyco.full()
from math import sqrt, ceil
import numpy as np

def rwh_primes(n):
    # /programming/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    """ Returns  a list of primes < n """
    sieve = [True] * n
    for i in xrange(3,int(n**0.5)+1,2):
        if sieve[i]:
            sieve[i*i::2*i]=[False]*((n-i*i-1)/(2*i)+1)
    return [2] + [i for i in xrange(3,n,2) if sieve[i]]

def rwh_primes1(n):
    # /programming/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    """ Returns  a list of primes < n """
    sieve = [True] * (n/2)
    for i in xrange(3,int(n**0.5)+1,2):
        if sieve[i/2]:
            sieve[i*i/2::i] = [False] * ((n-i*i-1)/(2*i)+1)
    return [2] + [2*i+1 for i in xrange(1,n/2) if sieve[i]]

def rwh_primes2(n):
    # /programming/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    """ Input n>=6, Returns a list of primes, 2 <= p < n """
    correction = (n%6>1)
    n = {0:n,1:n-1,2:n+4,3:n+3,4:n+2,5:n+1}[n%6]
    sieve = [True] * (n/3)
    sieve[0] = False
    for i in xrange(int(n**0.5)/3+1):
      if sieve[i]:
        k=3*i+1|1
        sieve[      ((k*k)/3)      ::2*k]=[False]*((n/6-(k*k)/6-1)/k+1)
        sieve[(k*k+4*k-2*k*(i&1))/3::2*k]=[False]*((n/6-(k*k+4*k-2*k*(i&1))/6-1)/k+1)
    return [2,3] + [3*i+1|1 for i in xrange(1,n/3-correction) if sieve[i]]

def sieve_wheel_30(N):
    # http://zerovolt.com/?p=88
    ''' Returns a list of primes <= N using wheel criterion 2*3*5 = 30

Copyright 2009 by zerovolt.com
This code is free for non-commercial purposes, in which case you can just leave this comment as a credit for my work.
If you need this code for commercial purposes, please contact me by sending an email to: info [at] zerovolt [dot] com.'''
    __smallp = ( 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
    61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139,
    149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
    229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311,
    313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401,
    409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491,
    499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599,
    601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683,
    691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797,
    809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887,
    907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997)

    wheel = (2, 3, 5)
    const = 30
    if N < 2:
        return []
    if N <= const:
        pos = 0
        while __smallp[pos] <= N:
            pos += 1
        return list(__smallp[:pos])
    # make the offsets list
    offsets = (7, 11, 13, 17, 19, 23, 29, 1)
    # prepare the list
    p = [2, 3, 5]
    dim = 2 + N // const
    tk1  = [True] * dim
    tk7  = [True] * dim
    tk11 = [True] * dim
    tk13 = [True] * dim
    tk17 = [True] * dim
    tk19 = [True] * dim
    tk23 = [True] * dim
    tk29 = [True] * dim
    tk1[0] = False
    # help dictionary d
    # d[a , b] = c  ==> if I want to find the smallest useful multiple of (30*pos)+a
    # on tkc, then I need the index given by the product of [(30*pos)+a][(30*pos)+b]
    # in general. If b < a, I need [(30*pos)+a][(30*(pos+1))+b]
    d = {}
    for x in offsets:
        for y in offsets:
            res = (x*y) % const
            if res in offsets:
                d[(x, res)] = y
    # another help dictionary: gives tkx calling tmptk[x]
    tmptk = {1:tk1, 7:tk7, 11:tk11, 13:tk13, 17:tk17, 19:tk19, 23:tk23, 29:tk29}
    pos, prime, lastadded, stop = 0, 0, 0, int(ceil(sqrt(N)))
    # inner functions definition
    def del_mult(tk, start, step):
        for k in xrange(start, len(tk), step):
            tk[k] = False
    # end of inner functions definition
    cpos = const * pos
    while prime < stop:
        # 30k + 7
        if tk7[pos]:
            prime = cpos + 7
            p.append(prime)
            lastadded = 7
            for off in offsets:
                tmp = d[(7, off)]
                start = (pos + prime) if off == 7 else (prime * (const * (pos + 1 if tmp < 7 else 0) + tmp) )//const
                del_mult(tmptk[off], start, prime)
        # 30k + 11
        if tk11[pos]:
            prime = cpos + 11
            p.append(prime)
            lastadded = 11
            for off in offsets:
                tmp = d[(11, off)]
                start = (pos + prime) if off == 11 else (prime * (const * (pos + 1 if tmp < 11 else 0) + tmp) )//const
                del_mult(tmptk[off], start, prime)
        # 30k + 13
        if tk13[pos]:
            prime = cpos + 13
            p.append(prime)
            lastadded = 13
            for off in offsets:
                tmp = d[(13, off)]
                start = (pos + prime) if off == 13 else (prime * (const * (pos + 1 if tmp < 13 else 0) + tmp) )//const
                del_mult(tmptk[off], start, prime)
        # 30k + 17
        if tk17[pos]:
            prime = cpos + 17
            p.append(prime)
            lastadded = 17
            for off in offsets:
                tmp = d[(17, off)]
                start = (pos + prime) if off == 17 else (prime * (const * (pos + 1 if tmp < 17 else 0) + tmp) )//const
                del_mult(tmptk[off], start, prime)
        # 30k + 19
        if tk19[pos]:
            prime = cpos + 19
            p.append(prime)
            lastadded = 19
            for off in offsets:
                tmp = d[(19, off)]
                start = (pos + prime) if off == 19 else (prime * (const * (pos + 1 if tmp < 19 else 0) + tmp) )//const
                del_mult(tmptk[off], start, prime)
        # 30k + 23
        if tk23[pos]:
            prime = cpos + 23
            p.append(prime)
            lastadded = 23
            for off in offsets:
                tmp = d[(23, off)]
                start = (pos + prime) if off == 23 else (prime * (const * (pos + 1 if tmp < 23 else 0) + tmp) )//const
                del_mult(tmptk[off], start, prime)
        # 30k + 29
        if tk29[pos]:
            prime = cpos + 29
            p.append(prime)
            lastadded = 29
            for off in offsets:
                tmp = d[(29, off)]
                start = (pos + prime) if off == 29 else (prime * (const * (pos + 1 if tmp < 29 else 0) + tmp) )//const
                del_mult(tmptk[off], start, prime)
        # now we go back to top tk1, so we need to increase pos by 1
        pos += 1
        cpos = const * pos
        # 30k + 1
        if tk1[pos]:
            prime = cpos + 1
            p.append(prime)
            lastadded = 1
            for off in offsets:
                tmp = d[(1, off)]
                start = (pos + prime) if off == 1 else (prime * (const * pos + tmp) )//const
                del_mult(tmptk[off], start, prime)
    # time to add remaining primes
    # if lastadded == 1, remove last element and start adding them from tk1
    # this way we don't need an "if" within the last while
    if lastadded == 1:
        p.pop()
    # now complete for every other possible prime
    while pos < len(tk1):
        cpos = const * pos
        if tk1[pos]: p.append(cpos + 1)
        if tk7[pos]: p.append(cpos + 7)
        if tk11[pos]: p.append(cpos + 11)
        if tk13[pos]: p.append(cpos + 13)
        if tk17[pos]: p.append(cpos + 17)
        if tk19[pos]: p.append(cpos + 19)
        if tk23[pos]: p.append(cpos + 23)
        if tk29[pos]: p.append(cpos + 29)
        pos += 1
    # remove exceeding if present
    pos = len(p) - 1
    while p[pos] > N:
        pos -= 1
    if pos < len(p) - 1:
        del p[pos+1:]
    # return p list
    return p

def sieveOfEratosthenes(n):
    """sieveOfEratosthenes(n): return the list of the primes < n."""
    # Code from: <dickinsm@gmail.com>, Nov 30 2006
    # http://groups.google.com/group/comp.lang.python/msg/f1f10ced88c68c2d
    if n <= 2:
        return []
    sieve = range(3, n, 2)
    top = len(sieve)
    for si in sieve:
        if si:
            bottom = (si*si - 3) // 2
            if bottom >= top:
                break
            sieve[bottom::si] = [0] * -((bottom - top) // si)
    return [2] + [el for el in sieve if el]

def sieveOfAtkin(end):
    """sieveOfAtkin(end): return a list of all the prime numbers <end
    using the Sieve of Atkin."""
    # Code by Steve Krenzel, <Sgk284@gmail.com>, improved
    # Code: https://web.archive.org/web/20080324064651/http://krenzel.info/?p=83
    # Info: http://en.wikipedia.org/wiki/Sieve_of_Atkin
    assert end > 0
    lng = ((end-1) // 2)
    sieve = [False] * (lng + 1)

    x_max, x2, xd = int(sqrt((end-1)/4.0)), 0, 4
    for xd in xrange(4, 8*x_max + 2, 8):
        x2 += xd
        y_max = int(sqrt(end-x2))
        n, n_diff = x2 + y_max*y_max, (y_max << 1) - 1
        if not (n & 1):
            n -= n_diff
            n_diff -= 2
        for d in xrange((n_diff - 1) << 1, -1, -8):
            m = n % 12
            if m == 1 or m == 5:
                m = n >> 1
                sieve[m] = not sieve[m]
            n -= d

    x_max, x2, xd = int(sqrt((end-1) / 3.0)), 0, 3
    for xd in xrange(3, 6 * x_max + 2, 6):
        x2 += xd
        y_max = int(sqrt(end-x2))
        n, n_diff = x2 + y_max*y_max, (y_max << 1) - 1
        if not(n & 1):
            n -= n_diff
            n_diff -= 2
        for d in xrange((n_diff - 1) << 1, -1, -8):
            if n % 12 == 7:
                m = n >> 1
                sieve[m] = not sieve[m]
            n -= d

    x_max, y_min, x2, xd = int((2 + sqrt(4-8*(1-end)))/4), -1, 0, 3
    for x in xrange(1, x_max + 1):
        x2 += xd
        xd += 6
        if x2 >= end: y_min = (((int(ceil(sqrt(x2 - end))) - 1) << 1) - 2) << 1
        n, n_diff = ((x*x + x) << 1) - 1, (((x-1) << 1) - 2) << 1
        for d in xrange(n_diff, y_min, -8):
            if n % 12 == 11:
                m = n >> 1
                sieve[m] = not sieve[m]
            n += d

    primes = [2, 3]
    if end <= 3:
        return primes[:max(0,end-2)]

    for n in xrange(5 >> 1, (int(sqrt(end))+1) >> 1):
        if sieve[n]:
            primes.append((n << 1) + 1)
            aux = (n << 1) + 1
            aux *= aux
            for k in xrange(aux, end, 2 * aux):
                sieve[k >> 1] = False

    s  = int(sqrt(end)) + 1
    if s  % 2 == 0:
        s += 1
    primes.extend([i for i in xrange(s, end, 2) if sieve[i >> 1]])

    return primes

def ambi_sieve_plain(n):
    s = range(3, n, 2)
    for m in xrange(3, int(n**0.5)+1, 2): 
        if s[(m-3)/2]: 
            for t in xrange((m*m-3)/2,(n>>1)-1,m):
                s[t]=0
    return [2]+[t for t in s if t>0]

def sundaram3(max_n):
    # /programming/2068372/fastest-way-to-list-all-primes-below-n-in-python/2073279#2073279
    numbers = range(3, max_n+1, 2)
    half = (max_n)//2
    initial = 4

    for step in xrange(3, max_n+1, 2):
        for i in xrange(initial, half, step):
            numbers[i-1] = 0
        initial += 2*(step+1)

        if initial > half:
            return [2] + filter(None, numbers)

################################################################################
# Using Numpy:
def ambi_sieve(n):
    # http://tommih.blogspot.com/2009/04/fast-prime-number-generator.html
    s = np.arange(3, n, 2)
    for m in xrange(3, int(n ** 0.5)+1, 2): 
        if s[(m-3)/2]: 
            s[(m*m-3)/2::m]=0
    return np.r_[2, s[s>0]]

def primesfrom3to(n):
    # /programming/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    """ Returns a array of primes, p < n """
    assert n>=2
    sieve = np.ones(n/2, dtype=np.bool)
    for i in xrange(3,int(n**0.5)+1,2):
        if sieve[i/2]:
            sieve[i*i/2::i] = False
    return np.r_[2, 2*np.nonzero(sieve)[0][1::]+1]    

def primesfrom2to(n):
    # /programming/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    """ Input n>=6, Returns a array of primes, 2 <= p < n """
    sieve = np.ones(n/3 + (n%6==2), dtype=np.bool)
    sieve[0] = False
    for i in xrange(int(n**0.5)/3+1):
        if sieve[i]:
            k=3*i+1|1
            sieve[      ((k*k)/3)      ::2*k] = False
            sieve[(k*k+4*k-2*k*(i&1))/3::2*k] = False
    return np.r_[2,3,((3*np.nonzero(sieve)[0]+1)|1)]

if __name__=='__main__':
    import itertools
    import sys

    def test(f1,f2,num):
        print('Testing {f1} and {f2} return same results'.format(
            f1=f1.func_name,
            f2=f2.func_name))
        if not all([a==b for a,b in itertools.izip_longest(f1(num),f2(num))]):
            sys.exit("Error: %s(%s) != %s(%s)"%(f1.func_name,num,f2.func_name,num))

    n=1000000
    test(sieveOfAtkin,sieveOfEratosthenes,n)
    test(sieveOfAtkin,ambi_sieve,n)
    test(sieveOfAtkin,ambi_sieve_plain,n) 
    test(sieveOfAtkin,sundaram3,n)
    test(sieveOfAtkin,sieve_wheel_30,n)
    test(sieveOfAtkin,primesfrom3to,n)
    test(sieveOfAtkin,primesfrom2to,n)
    test(sieveOfAtkin,rwh_primes,n)
    test(sieveOfAtkin,rwh_primes1,n)         
    test(sieveOfAtkin,rwh_primes2,n)

Komut dosyası çalıştırma, tüm uygulamaların aynı sonucu verdiğini test eder.


4
Saf olmayan Python koduyla ilgileniyorsanız, kontrol etmelisiniz gmpy- türünün next_primeyöntemi ile primerler için oldukça iyi bir desteği vardır mpz.
Alex Martelli

1
Pypy kullanıyorsanız, bu kriterler (psyco olanlar) oldukça kapalı görünüyor. Şaşırtıcı bir şekilde, sieveOfEratosthenes ve ambi_sieve_plain'i pypy ile en hızlı buldum. Bu numpy olmayanlar için bulduğum şey gist.github.com/5bf466bb1ee9e5726a52
Ehsan Kia

1
Birisi buradaki işlevlerin, psyco veya pypy olmadan saf python için Wikibooks'un PG7.8'e karşı ücretini merak ederse: n = 1000000: PG7.8: döngü başına 4.93 s; rwh_primes1: döngü başına 69 ms; rwh_primes2: döngü başına 57,1 ms
gaborous

8
Bunu PyPy ile güncelleyebilir misiniz, şimdi psyco öldü ve PyPy yerini aldı mı?
noɥʇʎԀʎzɐɹƆ

3
Bu işlevler ve zamanlamalar python3 için güncellenebilseydi harika olurdu.
cs95

135

Daha hızlı ve daha fazla bellek açısından saf Python kodu:

def primes(n):
    """ Returns  a list of primes < n """
    sieve = [True] * n
    for i in range(3,int(n**0.5)+1,2):
        if sieve[i]:
            sieve[i*i::2*i]=[False]*((n-i*i-1)//(2*i)+1)
    return [2] + [i for i in range(3,n,2) if sieve[i]]

veya yarım elek ile başlayarak

def primes1(n):
    """ Returns  a list of primes < n """
    sieve = [True] * (n//2)
    for i in range(3,int(n**0.5)+1,2):
        if sieve[i//2]:
            sieve[i*i//2::i] = [False] * ((n-i*i-1)//(2*i)+1)
    return [2] + [2*i+1 for i in range(1,n//2) if sieve[i]]

Daha hızlı ve daha fazla bellek açısından numpy kodu:

import numpy
def primesfrom3to(n):
    """ Returns a array of primes, 3 <= p < n """
    sieve = numpy.ones(n//2, dtype=numpy.bool)
    for i in range(3,int(n**0.5)+1,2):
        if sieve[i//2]:
            sieve[i*i//2::i] = False
    return 2*numpy.nonzero(sieve)[0][1::]+1

eleklerin üçte birinden başlayarak daha hızlı bir varyasyon:

import numpy
def primesfrom2to(n):
    """ Input n>=6, Returns a array of primes, 2 <= p < n """
    sieve = numpy.ones(n//3 + (n%6==2), dtype=numpy.bool)
    for i in range(1,int(n**0.5)//3+1):
        if sieve[i]:
            k=3*i+1|1
            sieve[       k*k//3     ::2*k] = False
            sieve[k*(k-2*(i&1)+4)//3::2*k] = False
    return numpy.r_[2,3,((3*numpy.nonzero(sieve)[0][1:]+1)|1)]

Yukarıdaki kodun (kodlanması zor) saf python sürümü şöyle olacaktır:

def primes2(n):
    """ Input n>=6, Returns a list of primes, 2 <= p < n """
    n, correction = n-n%6+6, 2-(n%6>1)
    sieve = [True] * (n//3)
    for i in range(1,int(n**0.5)//3+1):
      if sieve[i]:
        k=3*i+1|1
        sieve[      k*k//3      ::2*k] = [False] * ((n//6-k*k//6-1)//k+1)
        sieve[k*(k-2*(i&1)+4)//3::2*k] = [False] * ((n//6-k*(k-2*(i&1)+4)//6-1)//k+1)
    return [2,3] + [3*i+1|1 for i in range(1,n//3-correction) if sieve[i]]

Ne yazık ki saf-python, atama yapmanın daha basit ve daha hızlı numpy yolunu benimsemez len()ve döngü içinde [False]*len(sieve[((k*k)//3)::2*k])olduğu gibi çağırmak çok yavaştır. Bu yüzden girişi düzeltmek (ve daha fazla matematik önlemek) ve bazı aşırı (ve acı verici) matematik-sihir yapmak için doğaçlama gerekiyordu.

Şahsen, numpy'nin (bu kadar yaygın olarak kullanılan) Python standart kütüphanesinin bir parçası olmaması ve sözdizimi ve hızdaki gelişmelerin Python geliştiricileri tarafından tamamen göz ardı edildiği bir utanç olduğunu düşünüyorum.


2
Numpy artık Python 3 ile uyumludur. Standart kütüphanede olmadığı gerçeği iyidir, bu şekilde kendi yayın döngülerine sahip olabilirler.
Adam

ikili değerleri sadece önerdiğim bir dizide saklamak için bitarray- burada kullanıldığı gibi (en basit ana elek için; burada yarışta bir rakip değil!) stackoverflow.com/questions/31120986/…
hiro kahramanı

primesfrom2to()Yönteme döküm yaparken , bölüm parantez içinde olmalı mı?
355durch113

3
Python 3 ile uyumlu saf bir python sürümü için şu bağlantıyı izleyin: stackoverflow.com/a/33356284/2482582
Moebius

1
Bu enayi hızlı olan kutsal buttsnacks.
Scott

42

Burada Python Yemek Kitabı'ndan oldukça düzgün bir örnek var - bu URL'de önerilen en hızlı sürüm:

import itertools
def erat2( ):
    D = {  }
    yield 2
    for q in itertools.islice(itertools.count(3), 0, None, 2):
        p = D.pop(q, None)
        if p is None:
            D[q*q] = q
            yield q
        else:
            x = p + q
            while x in D or not (x&1):
                x += p
            D[x] = p

böylece verirdi

def get_primes_erat(n):
  return list(itertools.takewhile(lambda p: p<n, erat2()))

Kabuk isteminde (yapmayı tercih ettiğim gibi) pri.py'deki bu kodla ölçme, gözlemliyorum:

$ python2.5 -mtimeit -s'import pri' 'pri.get_primes(1000000)'
10 loops, best of 3: 1.69 sec per loop
$ python2.5 -mtimeit -s'import pri' 'pri.get_primes_erat(1000000)'
10 loops, best of 3: 673 msec per loop

yani Cookbook çözümü iki kat daha hızlı.


1
@jbochi, hoş geldiniz - ancak krediler de dahil olmak üzere bu URL'ye bakın: Tim Peters ve Raymond Hettinger gibi Python performans armatürleri de dahil olmak üzere, kodu bu noktaya topluca rafine etmek on kişimizi aldı ( Basılı Yemek Kitabı'nı düzenlediğimden beri tarifin son metni, ancak kodlama açısından katkım diğerleriyle eşitti ') - sonunda, gerçekten ince ve ince ayarlanmış kod ve bu şaşırtıcı değil! -)
Alex Martelli

@Alex: Kodunuzun benimkinden iki kat daha hızlı "sadece" olduğunu bilmek beni gururlandırıyor. :) URL okumak da çok ilginçti. Tekrar teşekkürler.
jbochi

Ve küçük bir değişiklikle daha da hızlı hale getirilebilir: bkz. Stackoverflow.com/questions/2211990/…
tzot

1
... Ve henüz daha hızlı yapılabilir eklenmesini erteleyerek, ampirik zaman karmaşıklığının O (sqrt (n)) ve iyileştirme için ek ~ 1.2x-1.3x Speedup, O (n) den bellek ayak izi köklü azalma ile girişte kareleri görülene kadar dikteye asaldır . Burada test edin .
Ness

28

Sundaram'ın Elekini kullanarak saf Python'un rekorunu kırdım:

def sundaram3(max_n):
    numbers = range(3, max_n+1, 2)
    half = (max_n)//2
    initial = 4

    for step in xrange(3, max_n+1, 2):
        for i in xrange(initial, half, step):
            numbers[i-1] = 0
        initial += 2*(step+1)

        if initial > half:
            return [2] + filter(None, numbers)

Karşılaştırılması:

C:\USERS>python -m timeit -n10 -s "import get_primes" "get_primes.get_primes_erat(1000000)"
10 loops, best of 3: 710 msec per loop

C:\USERS>python -m timeit -n10 -s "import get_primes" "get_primes.daniel_sieve_2(1000000)"
10 loops, best of 3: 435 msec per loop

C:\USERS>python -m timeit -n10 -s "import get_primes" "get_primes.sundaram3(1000000)"
10 loops, best of 3: 327 msec per loop

1
İşlevin üstüne "sıfır = 0" ekleyerek ve ardından filtrenizdeki lambda'yı "sıfır .__ sub__" ile değiştirerek işlevinizi yaklaşık% 20 hızlandırmayı başardım. Dünyanın en güzel kodu değil, ama biraz daha hızlı :)
truppo

1
@truppo: Yorumunuz için teşekkürler! Sadece Noneorijinal fonksiyon yerine geçmenin işe yaradığını fark ettim ve daha da hızlızero.__sub__
jbochi

7
Eğer geçerseniz sundaram3(9)geri döneceğini biliyor muydunuz [2, 3, 5, 7, 9]? (Bunlar asal olmasalar bile) tek sayılar - belki de tüm - sayısız ile bunu gibi görünüyor
wrhall

1
bir sorunu var: sundaram3 (7071)
7071'i

18

Algoritma hızlıdır, ancak ciddi bir kusuru vardır:

>>> sorted(get_primes(530))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163,
167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251,
257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443,
449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 527, 529]
>>> 17*31
527
>>> 23*23
529

Bunun numbers.pop()setteki en küçük sayıyı döndüreceğini varsayıyorsunuz , ancak bu hiç garanti edilmez. Kümeler sıralanmamıştır ve isteğe bağlı bir öğeyi pop()kaldırır ve döndürür , bu nedenle kalan sayılardan bir sonraki asalı seçmek için kullanılamaz.


17

İçin gerçekten yeterince büyük N en hızlı çözümü bir indirmek olacaktır asal önceden hesaplanmış liste , bir demet olarak saklayın ve böyle bir şey yapmak:

for pos,i in enumerate(primes):
    if i > N:
        print primes[:pos]

Eğer N > primes[-1] sadece daha sonra asal hesaplamak ve, kodunuzda bu yüzden bir dahaki sefere yeni listesini kaydetmek o kadar hızlı eşit olduğunu.

Daima kutunun dışında düşünün.


9
Adil olmak gerekirse, primerlerin indirilmesi, unzip edilmesi ve biçimlendirilmesi için zaman saymanız ve bunu bir algoritma kullanarak prim üretme zamanı ile karşılaştırmanız gerekir - bu algoritmalardan herhangi biri sonuçları daha sonra kullanmak için bir dosyaya kolayca yazabilir kullanın. Bu durumda, 982,451,653'ten daha az olan tüm primerleri gerçekten hesaplamak için yeterli bellek verildiğinde, numpy çözümü hala daha hızlı olacaktır.
Daniel G

3
@ Daniel doğru. Ancak mağaza var ve ihtiyaç duyduğunuzda devam hala duruyor ...
Kimvais

@ Daniel GI indirme zamanının alakasız olduğunu düşünüyorum. Sayıları oluşturmakla ilgili değil, bu yüzden indirdiğiniz listeyi oluşturmak için kullanılan algoritmayı dikkate almak istersiniz. Ve herhangi bir zaman karmaşıklığı O (n) verildiğinde bir kez dosya aktarımını yok sayar.
Ross

SSS UTM asal sayfa için küçük asal hesaplanırken daha hızlı bir disk kapalı bunları okumaktan daha (soru ne küçük bir araçtır) olduğu belirtilmektedir.
Batman

12

Tekerleği yeniden icat etmek istemiyorsanız, sembolik matematik kütüphanesi semtini kurabilirsiniz (evet Python 3 uyumludur)

pip install sympy

Ve primerange işlevini kullanın

from sympy import sieve
primes = list(sieve.primerange(1, 10**6))

9

Itertools'u kabul edip numpy'yi kabul etmiyorsanız, Python 3 için rwh_primes2'nin makinemde yaklaşık iki kat daha hızlı çalışan bir uyarlaması. Tek önemli değişiklik, boole için bir liste yerine bytearray kullanmak ve son listeyi oluşturmak için liste kavrama yerine sıkıştırmayı kullanmaktır. (Bunu yapabilseydim bunu moarningsun gibi bir yorum olarak eklerdim.)

import itertools
izip = itertools.zip_longest
chain = itertools.chain.from_iterable
compress = itertools.compress
def rwh_primes2_python3(n):
    """ Input n>=6, Returns a list of primes, 2 <= p < n """
    zero = bytearray([False])
    size = n//3 + (n % 6 == 2)
    sieve = bytearray([True]) * size
    sieve[0] = False
    for i in range(int(n**0.5)//3+1):
      if sieve[i]:
        k=3*i+1|1
        start = (k*k+4*k-2*k*(i&1))//3
        sieve[(k*k)//3::2*k]=zero*((size - (k*k)//3 - 1) // (2 * k) + 1)
        sieve[  start ::2*k]=zero*((size -   start  - 1) // (2 * k) + 1)
    ans = [2,3]
    poss = chain(izip(*[range(i, n, 6) for i in (1,5)]))
    ans.extend(compress(poss, sieve))
    return ans

Karşılaştırmalar:

>>> timeit.timeit('primes.rwh_primes2(10**6)', setup='import primes', number=1)
0.0652179726976101
>>> timeit.timeit('primes.rwh_primes2_python3(10**6)', setup='import primes', number=1)
0.03267321276325674

ve

>>> timeit.timeit('primes.rwh_primes2(10**8)', setup='import primes', number=1)
6.394284538007014
>>> timeit.timeit('primes.rwh_primes2_python3(10**8)', setup='import primes', number=1)
3.833829450302801

7

Kendi birincil bulma kodunuzu yazmak öğreticidir, ancak elinizde hızlı ve güvenilir bir kütüphaneye sahip olmak da yararlıdır. C ++ kitaplığı primesieve etrafında primesieve-python adında bir sarmalayıcı yazdım

Dene pip install primesieve

import primesieve
primes = primesieve.generate_primes(10**8)

Karşılaştırılan hızı görmek isterdim.


OP'nin sipariş ettiği şey tam olarak bu değil, ancak neden aşağı oyu göremiyorum. Diğer dış modüllerin aksine 2,8 saniyelik bir çözüm. Kaynakta dişli olduğunu fark ettim, ne kadar iyi ölçeklendiğine dair herhangi bir test var mı?
ljetibo

@ljetibo şerefe. Darboğaz C ++ vektörünü Python listesine kopyalıyor gibi görünüyor, bu nedenle count_primesişlev çok daha hızlıgenerate_primes
Albay Panik

Bilgisayarımda rahatça 1e8'e kadar prim üretebilir (1e9 için MemoryError verir) ve 1e10'a kadar primer sayabilir. @HappyLeapSecond 1e6 için algoritmaları karşılaştırır
Albay Panic

7

İşte en hızlı işlevlerden birinin güncellenmiş iki (saf Python 3.6) sürümü,

from itertools import compress

def rwh_primes1v1(n):
    """ Returns  a list of primes < n for n > 2 """
    sieve = bytearray([True]) * (n//2)
    for i in range(3,int(n**0.5)+1,2):
        if sieve[i//2]:
            sieve[i*i//2::i] = bytearray((n-i*i-1)//(2*i)+1)
    return [2,*compress(range(3,n,2), sieve[1:])]

def rwh_primes1v2(n):
    """ Returns a list of primes < n for n > 2 """
    sieve = bytearray([True]) * (n//2+1)
    for i in range(1,int(n**0.5)//2+1):
        if sieve[i]:
            sieve[2*i*(i+1)::2*i+1] = bytearray((n//2-2*i*(i+1))//(2*i+1)+1)
    return [2,*compress(range(3,n,2), sieve[1:])]

1
Python 3'te bu işlevi stackoverflow.com/a/3035188/7799269 kullandım, ancak // ve xrange ile range ile değiştirdim ve bundan daha hızlı görünüyordu.
samerivertwice

4

Miller-Rabin'in Primality testinin N <9.080.191 olduğu varsayımı üzerine deterministik bir uygulaması

import sys
import random

def miller_rabin_pass(a, n):
    d = n - 1
    s = 0
    while d % 2 == 0:
        d >>= 1
        s += 1

    a_to_power = pow(a, d, n)
    if a_to_power == 1:
        return True
    for i in xrange(s-1):
        if a_to_power == n - 1:
            return True
        a_to_power = (a_to_power * a_to_power) % n
    return a_to_power == n - 1


def miller_rabin(n):
    for a in [2, 3, 37, 73]:
      if not miller_rabin_pass(a, n):
        return False
    return True


n = int(sys.argv[1])
primes = [2]
for p in range(3,n,2):
  if miller_rabin(p):
    primes.append(p)
print len(primes)

Wikipedia'daki makaleye göre ( http://en.wikipedia.org/wiki/Miller–Rabin_primality_test ) N <9,080,191'i = 2,3,37 ve 73 için test ederek N'nin bileşik olup olmadığına karar vermek yeterlidir.

Ve kaynak kodu, burada bulunan orijinal Miller-Rabin'in testinin olasılıklı uygulanmasından uyarladım: http://en.literateprograms.org/Miller-Rabin_primality_test_(Python)


1
Miller-Rabin öncelik testi için teşekkür ederiz, ancak bu kod aslında daha yavaştır ve doğru sonuçları sağlamamaktadır. 37 asaldır ve testi geçmez.
jbochi

Sanırım 37 özel durumlardan biri, benim hatam. Yine de deterministik versiyondan umutluyordum :)
Ruggiero Spearman

Rabin miller için özel bir durum yok.
Yanlış

2
Makaleyi yanlış okudun. Bu 37 değil, 31'dir. Bu yüzden uygulamanız başarısız olur.
Logan


4

İşte normalde Python primler oluşturmak için kullandığım kod:

$ python -mtimeit -s'import sieve' 'sieve.sieve(1000000)' 
10 loops, best of 3: 445 msec per loop
$ cat sieve.py
from math import sqrt

def sieve(size):
 prime=[True]*size
 rng=xrange
 limit=int(sqrt(size))

 for i in rng(3,limit+1,+2):
  if prime[i]:
   prime[i*i::+i]=[False]*len(prime[i*i::+i])

 return [2]+[i for i in rng(3,size,+2) if prime[i]]

if __name__=='__main__':
 print sieve(100)

Burada yayınlanan daha hızlı çözümlerle rekabet edemez, ama en azından saf python.

Bu soruyu gönderdiğiniz için teşekkür ederiz. Bugün gerçekten çok şey öğrendim.


3

En hızlı kod için, numpy çözümü en iyisidir. Tamamen akademik nedenlerden ötürü, yukarıda yayınlanan yemek kitabı versiyonundan% 50 daha hızlı olan saf python versiyonumu gönderiyorum. Listenin tamamını bellekte yaptığım için, her şeyi tutacak kadar alana ihtiyacınız var, ancak oldukça iyi ölçekleniyor gibi görünüyor.

def daniel_sieve_2(maxNumber):
    """
    Given a number, returns all numbers less than or equal to
    that number which are prime.
    """
    allNumbers = range(3, maxNumber+1, 2)
    for mIndex, number in enumerate(xrange(3, maxNumber+1, 2)):
        if allNumbers[mIndex] == 0:
            continue
        # now set all multiples to 0
        for index in xrange(mIndex+number, (maxNumber-3)/2+1, number):
            allNumbers[index] = 0
    return [2] + filter(lambda n: n!=0, allNumbers)

Ve sonuçlar:

>>>mine = timeit.Timer("daniel_sieve_2(1000000)",
...                    "from sieves import daniel_sieve_2")
>>>prev = timeit.Timer("get_primes_erat(1000000)",
...                    "from sieves import get_primes_erat")
>>>print "Mine: {0:0.4f} ms".format(min(mine.repeat(3, 1))*1000)
Mine: 428.9446 ms
>>>print "Previous Best {0:0.4f} ms".format(min(prev.repeat(3, 1))*1000)
Previous Best 621.3581 ms

3

Numpy kullanarak yarım bir elek biraz farklı bir uygulama:

http://rebrained.com/?p=458

matematik al
içe aktarma sayısı
def prime6 (yukarı):
    asal = numpy.arange (3, kadar + 1,2)
    isprime = numpy.ones ((kadar-1) / 2, d_type = BOOL)
    primerdeki faktör için [: int (math.sqrt (upto))]:
        isprime ise [(faktör-2) / 2]: isprime [(faktör * 3-2) / 2: (en fazla-1) / 2: faktör] = 0
    dönüş numpy.insert (asal [isprime], 0,2)

Birisi bunu diğer zamanlamalarla karşılaştırabilir mi? Makinemde diğer Numpy yarım elek ile oldukça benzer görünüyor.


upto=10**6: primesfrom2to()- 7 ms; prime6()- 12 ms ideone.com/oDg2Y
jfs

3

Hepsi yazılı ve test edilmiştir. Yani tekerleği yeniden icat etmeye gerek yok.

python -m timeit -r10 -s"from sympy import sieve" "primes = list(sieve.primerange(1, 10**6))"

bize 12,2 msn kırılma rekoru veriyor !

10 loops, best of 10: 12.2 msec per loop

Bu yeterince hızlı değilse, PyPy'yi deneyebilirsiniz:

pypy -m timeit -r10 -s"from sympy import sieve" "primes = list(sieve.primerange(1, 10**6))"

sonuç:

10 loops, best of 10: 2.03 msec per loop

247 yukarı oyla yanıt, en iyi çözüm için 15.9 ms listeliyor. Bunu karşılaştırın !!!


3

Bazı unutbu'nun işlevlerini test ettim, aç milyonlarca numarayla hesapladım

Kazananlar numpy kütüphanesini kullanan fonksiyonlardır,

Not : Ayrıca bir bellek kullanım testi yapmak ilginç olurdu :)

Hesaplama süresi sonucu

Basit kod

Github havuzumdaki tam kod

#!/usr/bin/env python

import lib
import timeit
import sys
import math
import datetime

import prettyplotlib as ppl
import numpy as np

import matplotlib.pyplot as plt
from prettyplotlib import brewer2mpl

primenumbers_gen = [
    'sieveOfEratosthenes',
    'ambi_sieve',
    'ambi_sieve_plain',
    'sundaram3',
    'sieve_wheel_30',
    'primesfrom3to',
    'primesfrom2to',
    'rwh_primes',
    'rwh_primes1',
    'rwh_primes2',
]

def human_format(num):
    # /programming/579310/formatting-long-numbers-as-strings-in-python?answertab=active#tab-top
    magnitude = 0
    while abs(num) >= 1000:
        magnitude += 1
        num /= 1000.0
    # add more suffixes if you need them
    return '%.2f%s' % (num, ['', 'K', 'M', 'G', 'T', 'P'][magnitude])


if __name__=='__main__':

    # Vars
    n = 10000000 # number itereration generator
    nbcol = 5 # For decompose prime number generator
    nb_benchloop = 3 # Eliminate false positive value during the test (bench average time)
    datetimeformat = '%Y-%m-%d %H:%M:%S.%f'
    config = 'from __main__ import n; import lib'
    primenumbers_gen = {
        'sieveOfEratosthenes': {'color': 'b'},
        'ambi_sieve': {'color': 'b'},
        'ambi_sieve_plain': {'color': 'b'},
         'sundaram3': {'color': 'b'},
        'sieve_wheel_30': {'color': 'b'},
# # #        'primesfrom2to': {'color': 'b'},
        'primesfrom3to': {'color': 'b'},
        # 'rwh_primes': {'color': 'b'},
        # 'rwh_primes1': {'color': 'b'},
        'rwh_primes2': {'color': 'b'},
    }


    # Get n in command line
    if len(sys.argv)>1:
        n = int(sys.argv[1])

    step = int(math.ceil(n / float(nbcol)))
    nbs = np.array([i * step for i in range(1, int(nbcol) + 1)])
    set2 = brewer2mpl.get_map('Paired', 'qualitative', 12).mpl_colors

    print datetime.datetime.now().strftime(datetimeformat)
    print("Compute prime number to %(n)s" % locals())
    print("")

    results = dict()
    for pgen in primenumbers_gen:
        results[pgen] = dict()
        benchtimes = list()
        for n in nbs:
            t = timeit.Timer("lib.%(pgen)s(n)" % locals(), setup=config)
            execute_times = t.repeat(repeat=nb_benchloop,number=1)
            benchtime = np.mean(execute_times)
            benchtimes.append(benchtime)
        results[pgen] = {'benchtimes':np.array(benchtimes)}

fig, ax = plt.subplots(1)
plt.ylabel('Computation time (in second)')
plt.xlabel('Numbers computed')
i = 0
for pgen in primenumbers_gen:

    bench = results[pgen]['benchtimes']
    avgs = np.divide(bench,nbs)
    avg = np.average(bench, weights=nbs)

    # Compute linear regression
    A = np.vstack([nbs, np.ones(len(nbs))]).T
    a, b = np.linalg.lstsq(A, nbs*avgs)[0]

    # Plot
    i += 1
    #label="%(pgen)s" % locals()
    #ppl.plot(nbs, nbs*avgs, label=label, lw=1, linestyle='--', color=set2[i % 12])
    label="%(pgen)s avg" % locals()
    ppl.plot(nbs, a * nbs + b, label=label, lw=2, color=set2[i % 12])
print datetime.datetime.now().strftime(datetimeformat)

ppl.legend(ax, loc='upper left', ncol=4)

# Change x axis label
ax.get_xaxis().get_major_formatter().set_scientific(False)
fig.canvas.draw()
labels = [human_format(int(item.get_text())) for item in ax.get_xticklabels()]

ax.set_xticklabels(labels)
ax = plt.gca()

plt.show()

2
algoritmik performansları karşılaştırmak için bir log-log ölçeğinde çizim yapmak daha iyidir .
Ness

3

Python 3 için

def rwh_primes2(n):
    correction = (n%6>1)
    n = {0:n,1:n-1,2:n+4,3:n+3,4:n+2,5:n+1}[n%6]
    sieve = [True] * (n//3)
    sieve[0] = False
    for i in range(int(n**0.5)//3+1):
      if sieve[i]:
        k=3*i+1|1
        sieve[      ((k*k)//3)      ::2*k]=[False]*((n//6-(k*k)//6-1)//k+1)
        sieve[(k*k+4*k-2*k*(i&1))//3::2*k]=[False]*((n//6-(k*k+4*k-2*k*(i&1))//6-1)//k+1)
    return [2,3] + [3*i+1|1 for i in range(1,n//3-correction) if sieve[i]]

3

Pure Python'daki en hızlı ana elek :

from itertools import compress

def half_sieve(n):
    """
    Returns a list of prime numbers less than `n`.
    """
    if n <= 2:
        return []
    sieve = bytearray([True]) * (n // 2)
    for i in range(3, int(n ** 0.5) + 1, 2):
        if sieve[i // 2]:
            sieve[i * i // 2::i] = bytearray((n - i * i - 1) // (2 * i) + 1)
    primes = list(compress(range(1, n, 2), sieve))
    primes[0] = 2
    return primes

Eratosthenes Eleği'ni hız ve bellek için optimize ettim .

Karşılaştırma

from time import clock
import platform

def benchmark(iterations, limit):
    start = clock()
    for x in range(iterations):
        half_sieve(limit)
    end = clock() - start
    print(f'{end/iterations:.4f} seconds for primes < {limit}')

if __name__ == '__main__':
    print(platform.python_version())
    print(platform.platform())
    print(platform.processor())
    it = 10
    for pw in range(4, 9):
        benchmark(it, 10**pw)

Çıktı

>>> 3.6.7
>>> Windows-10-10.0.17763-SP0
>>> Intel64 Family 6 Model 78 Stepping 3, GenuineIntel
>>> 0.0003 seconds for primes < 10000
>>> 0.0021 seconds for primes < 100000
>>> 0.0204 seconds for primes < 1000000
>>> 0.2389 seconds for primes < 10000000
>>> 2.6702 seconds for primes < 100000000

2

İlk kez python kullanarak, bu yüzden kullandığım yöntemlerden bazıları biraz hantal görünebilir. Ben sadece benim c ++ kodunu python dönüştürdü ve bu ne (python biraz slowww olsa da)

#!/usr/bin/env python
import time

def GetPrimes(n):

    Sieve = [1 for x in xrange(n)]

    Done = False
    w = 3

    while not Done:

        for q in xrange (3, n, 2):
            Prod = w*q
            if Prod < n:
                Sieve[Prod] = 0
            else:
                break

        if w > (n/2):
            Done = True
        w += 2

    return Sieve



start = time.clock()

d = 10000000
Primes = GetPrimes(d)

count = 1 #This is for 2

for x in xrange (3, d, 2):
    if Primes[x]:
        count+=1

elapsed = (time.clock() - start)
print "\nFound", count, "primes in", elapsed, "seconds!\n"

pythonw Primes.py

12.799119 saniyede 664579 prim bulundu!

#!/usr/bin/env python
import time

def GetPrimes2(n):

    Sieve = [1 for x in xrange(n)]

    for q in xrange (3, n, 2):
        k = q
        for y in xrange(k*3, n, k*2):
            Sieve[y] = 0

    return Sieve



start = time.clock()

d = 10000000
Primes = GetPrimes2(d)

count = 1 #This is for 2

for x in xrange (3, d, 2):
    if Primes[x]:
        count+=1

elapsed = (time.clock() - start)
print "\nFound", count, "primes in", elapsed, "seconds!\n"

pythonw Primes2.py

10.230172 saniyede 664579 prim bulundu!

#!/usr/bin/env python
import time

def GetPrimes3(n):

    Sieve = [1 for x in xrange(n)]

    for q in xrange (3, n, 2):
        k = q
        for y in xrange(k*k, n, k << 1):
            Sieve[y] = 0

    return Sieve



start = time.clock()

d = 10000000
Primes = GetPrimes3(d)

count = 1 #This is for 2

for x in xrange (3, d, 2):
    if Primes[x]:
        count+=1

elapsed = (time.clock() - start)
print "\nFound", count, "primes in", elapsed, "seconds!\n"

python Primes2.py

7.113776 saniyede 664579 prim bulundu!


2

Rekabetin birkaç yıl kapalı olduğunu biliyorum. ...

Yine de bu, elek ileri işlenirken uygun adımları kullanarak 2, 3 ve 5 katlarını atlamaya dayanan saf bir python prime elek için önerim. Yine de N <10 ^ 9 için @Robert William Hanks rwh_primes2 ve rwh_primes1 üstün çözümlerinden daha yavaştır. 1.5 * 10 ^ 8 üzerinde bir ctypes.c_ushort elek dizisi kullanarak bir şekilde bellek sınırlarına uyarlanabilir.

10 ^ 6

$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (1000000)" 10 döngü, döngü başına en iyi 3: 46,7 ms

karşılaştırmak için: $ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.rwh_primes1 (1000000)" 10 döngüler, en iyisi 3: 43.2 msn döngü başına: $ python -m timeit -s "import primeSieveSpeedprim" (1000000) "10 döngü, döngü başına en iyi 3: 34,5 msn

10 ^ 7

$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (10000000)" 10 döngü, döngü başına en iyi 3: 530 ms

karşılaştırmak için: $ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.rwh_primes1 (10000000)" 10 döngü, döngü başına 3'ün en iyisi: 494 msn: "pime "10000 döngü", döngü başına en iyi 3: 375 msn.

10 8

$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (100000000)" 10 döngü, döngü başına en iyi 3: 5.55 sn

karşılaştırmak için: $ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.rwh_primes1 (100000000)" 10 döngü, döngü başına en iyi 3: 5,33 sn: $ ​​python -m timeit -s "import primeSieveSpeedComp" "primeSpeedprim2" "10000 döngü", döngü başına en iyi 3: 3,95 sn.

10 ^ 9

$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (1000000000)" 10 döngü, döngü başına en iyi 3: 61,2 sn

karşılaştırmak için: $ python -mtimeit -n 3 -s "import primeSieveSpeedComp" "primeSieveSpeedComp.rwh_primes1 (1000000000)" 3 döngü, döngü başına en iyi 3: 97,8 sn

karşılaştırmak için: $ python -m timeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.rwh_primes2 (1000000000)" 10 döngü, döngü başına en iyi 3: 41,9 sn

Bu testleri incelemek için aşağıdaki kodu ubuntus primeSieveSpeedComp dosyasına kopyalayabilirsiniz.

def primeSieveSeq(MAX_Int):
    if MAX_Int > 5*10**8:
        import ctypes
        int16Array = ctypes.c_ushort * (MAX_Int >> 1)
        sieve = int16Array()
        #print 'uses ctypes "unsigned short int Array"'
    else:
        sieve = (MAX_Int >> 1) * [False]
        #print 'uses python list() of long long int'
    if MAX_Int < 10**8:
        sieve[4::3] = [True]*((MAX_Int - 8)/6+1)
        sieve[12::5] = [True]*((MAX_Int - 24)/10+1)
    r = [2, 3, 5]
    n = 0
    for i in xrange(int(MAX_Int**0.5)/30+1):
        n += 3
        if not sieve[n]:
            n2 = (n << 1) + 1
            r.append(n2)
            n2q = (n2**2) >> 1
            sieve[n2q::n2] = [True]*(((MAX_Int >> 1) - n2q - 1) / n2 + 1)
        n += 2
        if not sieve[n]:
            n2 = (n << 1) + 1
            r.append(n2)
            n2q = (n2**2) >> 1
            sieve[n2q::n2] = [True]*(((MAX_Int >> 1) - n2q - 1) / n2 + 1)
        n += 1
        if not sieve[n]:
            n2 = (n << 1) + 1
            r.append(n2)
            n2q = (n2**2) >> 1
            sieve[n2q::n2] = [True]*(((MAX_Int >> 1) - n2q - 1) / n2 + 1)
        n += 2
        if not sieve[n]:
            n2 = (n << 1) + 1
            r.append(n2)
            n2q = (n2**2) >> 1
            sieve[n2q::n2] = [True]*(((MAX_Int >> 1) - n2q - 1) / n2 + 1)
        n += 1
        if not sieve[n]:
            n2 = (n << 1) + 1
            r.append(n2)
            n2q = (n2**2) >> 1
            sieve[n2q::n2] = [True]*(((MAX_Int >> 1) - n2q - 1) / n2 + 1)
        n += 2
        if not sieve[n]:
            n2 = (n << 1) + 1
            r.append(n2)
            n2q = (n2**2) >> 1
            sieve[n2q::n2] = [True]*(((MAX_Int >> 1) - n2q - 1) / n2 + 1)
        n += 3
        if not sieve[n]:
            n2 = (n << 1) + 1
            r.append(n2)
            n2q = (n2**2) >> 1
            sieve[n2q::n2] = [True]*(((MAX_Int >> 1) - n2q - 1) / n2 + 1)
        n += 1
        if not sieve[n]:
            n2 = (n << 1) + 1
            r.append(n2)
            n2q = (n2**2) >> 1
            sieve[n2q::n2] = [True]*(((MAX_Int >> 1) - n2q - 1) / n2 + 1)
    if MAX_Int < 10**8:
        return [2, 3, 5]+[(p << 1) + 1 for p in [n for n in xrange(3, MAX_Int >> 1) if not sieve[n]]]
    n = n >> 1
    try:
        for i in xrange((MAX_Int-2*n)/30 + 1):
            n += 3
            if not sieve[n]:
                r.append((n << 1) + 1)
            n += 2
            if not sieve[n]:
                r.append((n << 1) + 1)
            n += 1
            if not sieve[n]:
                r.append((n << 1) + 1)
            n += 2
            if not sieve[n]:
                r.append((n << 1) + 1)
            n += 1
            if not sieve[n]:
                r.append((n << 1) + 1)
            n += 2
            if not sieve[n]:
                r.append((n << 1) + 1)
            n += 3
            if not sieve[n]:
                r.append((n << 1) + 1)
            n += 1
            if not sieve[n]:
                r.append((n << 1) + 1)
    except:
        pass
    return r

test sonuçlarınızı görselleştirmek, deney-log ölçeğinde çizmek , ampirik büyüme düzenlerini görmek ve karşılaştırmak .
Ness

@ Giriş için teşekkürler olacak, ben böyle bir karşılaştırma gerektiğinde bir dahaki sefere aklımda olacak
ABri

1

Burada Eratosthenes'in Sieve'nin hem iyi karmaşıklığa (n uzunluğunun bir dizisini sıralamaktan daha düşük) hem de vektörleştirmeye sahip nümerik bir versiyonu. @Unutbu ile karşılaştırıldığında bu, 46 mikrosanetli paketlerin bir milyonun altındaki tüm primerleri bulmak kadar hızlıdır.

import numpy as np 
def generate_primes(n):
    is_prime = np.ones(n+1,dtype=bool)
    is_prime[0:2] = False
    for i in range(int(n**0.5)+1):
        if is_prime[i]:
            is_prime[i**2::i]=False
    return np.where(is_prime)[0]

Zamanlamaları:

import time    
for i in range(2,10):
    timer =time.time()
    generate_primes(10**i)
    print('n = 10^',i,' time =', round(time.time()-timer,6))

>> n = 10^ 2  time = 5.6e-05
>> n = 10^ 3  time = 6.4e-05
>> n = 10^ 4  time = 0.000114
>> n = 10^ 5  time = 0.000593
>> n = 10^ 6  time = 0.00467
>> n = 10^ 7  time = 0.177758
>> n = 10^ 8  time = 1.701312
>> n = 10^ 9  time = 19.322478

1

Python 3 için kodun çoğunu güncelledim ve gerçekten en hızlı olduğunu görmek için perfplot'a (benim bir projem) attım . Görünüşe göre, büyük ölçüde n, primesfrom{2,3}topastayı al:

resim açıklamasını buraya girin


Grafiği yeniden oluşturmak için kod:

import perfplot
from math import sqrt, ceil
import numpy as np
import sympy


def rwh_primes(n):
    # /programming/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    """ Returns  a list of primes < n """
    sieve = [True] * n
    for i in range(3, int(n ** 0.5) + 1, 2):
        if sieve[i]:
            sieve[i * i::2 * i] = [False] * ((n - i * i - 1) // (2 * i) + 1)
    return [2] + [i for i in range(3, n, 2) if sieve[i]]


def rwh_primes1(n):
    # /programming/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    """ Returns  a list of primes < n """
    sieve = [True] * (n // 2)
    for i in range(3, int(n ** 0.5) + 1, 2):
        if sieve[i // 2]:
            sieve[i * i // 2::i] = [False] * ((n - i * i - 1) // (2 * i) + 1)
    return [2] + [2 * i + 1 for i in range(1, n // 2) if sieve[i]]


def rwh_primes2(n):
    # /programming/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    """Input n>=6, Returns a list of primes, 2 <= p < n"""
    assert n >= 6
    correction = n % 6 > 1
    n = {0: n, 1: n - 1, 2: n + 4, 3: n + 3, 4: n + 2, 5: n + 1}[n % 6]
    sieve = [True] * (n // 3)
    sieve[0] = False
    for i in range(int(n ** 0.5) // 3 + 1):
        if sieve[i]:
            k = 3 * i + 1 | 1
            sieve[((k * k) // 3)::2 * k] = [False] * (
                (n // 6 - (k * k) // 6 - 1) // k + 1
            )
            sieve[(k * k + 4 * k - 2 * k * (i & 1)) // 3::2 * k] = [False] * (
                (n // 6 - (k * k + 4 * k - 2 * k * (i & 1)) // 6 - 1) // k + 1
            )
    return [2, 3] + [3 * i + 1 | 1 for i in range(1, n // 3 - correction) if sieve[i]]


def sieve_wheel_30(N):
    # http://zerovolt.com/?p=88
    """ Returns a list of primes <= N using wheel criterion 2*3*5 = 30

Copyright 2009 by zerovolt.com
This code is free for non-commercial purposes, in which case you can just leave this comment as a credit for my work.
If you need this code for commercial purposes, please contact me by sending an email to: info [at] zerovolt [dot] com."""
    __smallp = (
        2,
        3,
        5,
        7,
        11,
        13,
        17,
        19,
        23,
        29,
        31,
        37,
        41,
        43,
        47,
        53,
        59,
        61,
        67,
        71,
        73,
        79,
        83,
        89,
        97,
        101,
        103,
        107,
        109,
        113,
        127,
        131,
        137,
        139,
        149,
        151,
        157,
        163,
        167,
        173,
        179,
        181,
        191,
        193,
        197,
        199,
        211,
        223,
        227,
        229,
        233,
        239,
        241,
        251,
        257,
        263,
        269,
        271,
        277,
        281,
        283,
        293,
        307,
        311,
        313,
        317,
        331,
        337,
        347,
        349,
        353,
        359,
        367,
        373,
        379,
        383,
        389,
        397,
        401,
        409,
        419,
        421,
        431,
        433,
        439,
        443,
        449,
        457,
        461,
        463,
        467,
        479,
        487,
        491,
        499,
        503,
        509,
        521,
        523,
        541,
        547,
        557,
        563,
        569,
        571,
        577,
        587,
        593,
        599,
        601,
        607,
        613,
        617,
        619,
        631,
        641,
        643,
        647,
        653,
        659,
        661,
        673,
        677,
        683,
        691,
        701,
        709,
        719,
        727,
        733,
        739,
        743,
        751,
        757,
        761,
        769,
        773,
        787,
        797,
        809,
        811,
        821,
        823,
        827,
        829,
        839,
        853,
        857,
        859,
        863,
        877,
        881,
        883,
        887,
        907,
        911,
        919,
        929,
        937,
        941,
        947,
        953,
        967,
        971,
        977,
        983,
        991,
        997,
    )
    # wheel = (2, 3, 5)
    const = 30
    if N < 2:
        return []
    if N <= const:
        pos = 0
        while __smallp[pos] <= N:
            pos += 1
        return list(__smallp[:pos])
    # make the offsets list
    offsets = (7, 11, 13, 17, 19, 23, 29, 1)
    # prepare the list
    p = [2, 3, 5]
    dim = 2 + N // const
    tk1 = [True] * dim
    tk7 = [True] * dim
    tk11 = [True] * dim
    tk13 = [True] * dim
    tk17 = [True] * dim
    tk19 = [True] * dim
    tk23 = [True] * dim
    tk29 = [True] * dim
    tk1[0] = False
    # help dictionary d
    # d[a , b] = c  ==> if I want to find the smallest useful multiple of (30*pos)+a
    # on tkc, then I need the index given by the product of [(30*pos)+a][(30*pos)+b]
    # in general. If b < a, I need [(30*pos)+a][(30*(pos+1))+b]
    d = {}
    for x in offsets:
        for y in offsets:
            res = (x * y) % const
            if res in offsets:
                d[(x, res)] = y
    # another help dictionary: gives tkx calling tmptk[x]
    tmptk = {1: tk1, 7: tk7, 11: tk11, 13: tk13, 17: tk17, 19: tk19, 23: tk23, 29: tk29}
    pos, prime, lastadded, stop = 0, 0, 0, int(ceil(sqrt(N)))

    # inner functions definition
    def del_mult(tk, start, step):
        for k in range(start, len(tk), step):
            tk[k] = False

    # end of inner functions definition
    cpos = const * pos
    while prime < stop:
        # 30k + 7
        if tk7[pos]:
            prime = cpos + 7
            p.append(prime)
            lastadded = 7
            for off in offsets:
                tmp = d[(7, off)]
                start = (
                    (pos + prime)
                    if off == 7
                    else (prime * (const * (pos + 1 if tmp < 7 else 0) + tmp)) // const
                )
                del_mult(tmptk[off], start, prime)
        # 30k + 11
        if tk11[pos]:
            prime = cpos + 11
            p.append(prime)
            lastadded = 11
            for off in offsets:
                tmp = d[(11, off)]
                start = (
                    (pos + prime)
                    if off == 11
                    else (prime * (const * (pos + 1 if tmp < 11 else 0) + tmp)) // const
                )
                del_mult(tmptk[off], start, prime)
        # 30k + 13
        if tk13[pos]:
            prime = cpos + 13
            p.append(prime)
            lastadded = 13
            for off in offsets:
                tmp = d[(13, off)]
                start = (
                    (pos + prime)
                    if off == 13
                    else (prime * (const * (pos + 1 if tmp < 13 else 0) + tmp)) // const
                )
                del_mult(tmptk[off], start, prime)
        # 30k + 17
        if tk17[pos]:
            prime = cpos + 17
            p.append(prime)
            lastadded = 17
            for off in offsets:
                tmp = d[(17, off)]
                start = (
                    (pos + prime)
                    if off == 17
                    else (prime * (const * (pos + 1 if tmp < 17 else 0) + tmp)) // const
                )
                del_mult(tmptk[off], start, prime)
        # 30k + 19
        if tk19[pos]:
            prime = cpos + 19
            p.append(prime)
            lastadded = 19
            for off in offsets:
                tmp = d[(19, off)]
                start = (
                    (pos + prime)
                    if off == 19
                    else (prime * (const * (pos + 1 if tmp < 19 else 0) + tmp)) // const
                )
                del_mult(tmptk[off], start, prime)
        # 30k + 23
        if tk23[pos]:
            prime = cpos + 23
            p.append(prime)
            lastadded = 23
            for off in offsets:
                tmp = d[(23, off)]
                start = (
                    (pos + prime)
                    if off == 23
                    else (prime * (const * (pos + 1 if tmp < 23 else 0) + tmp)) // const
                )
                del_mult(tmptk[off], start, prime)
        # 30k + 29
        if tk29[pos]:
            prime = cpos + 29
            p.append(prime)
            lastadded = 29
            for off in offsets:
                tmp = d[(29, off)]
                start = (
                    (pos + prime)
                    if off == 29
                    else (prime * (const * (pos + 1 if tmp < 29 else 0) + tmp)) // const
                )
                del_mult(tmptk[off], start, prime)
        # now we go back to top tk1, so we need to increase pos by 1
        pos += 1
        cpos = const * pos
        # 30k + 1
        if tk1[pos]:
            prime = cpos + 1
            p.append(prime)
            lastadded = 1
            for off in offsets:
                tmp = d[(1, off)]
                start = (
                    (pos + prime)
                    if off == 1
                    else (prime * (const * pos + tmp)) // const
                )
                del_mult(tmptk[off], start, prime)
    # time to add remaining primes
    # if lastadded == 1, remove last element and start adding them from tk1
    # this way we don't need an "if" within the last while
    if lastadded == 1:
        p.pop()
    # now complete for every other possible prime
    while pos < len(tk1):
        cpos = const * pos
        if tk1[pos]:
            p.append(cpos + 1)
        if tk7[pos]:
            p.append(cpos + 7)
        if tk11[pos]:
            p.append(cpos + 11)
        if tk13[pos]:
            p.append(cpos + 13)
        if tk17[pos]:
            p.append(cpos + 17)
        if tk19[pos]:
            p.append(cpos + 19)
        if tk23[pos]:
            p.append(cpos + 23)
        if tk29[pos]:
            p.append(cpos + 29)
        pos += 1
    # remove exceeding if present
    pos = len(p) - 1
    while p[pos] > N:
        pos -= 1
    if pos < len(p) - 1:
        del p[pos + 1 :]
    # return p list
    return p


def sieve_of_eratosthenes(n):
    """sieveOfEratosthenes(n): return the list of the primes < n."""
    # Code from: <dickinsm@gmail.com>, Nov 30 2006
    # http://groups.google.com/group/comp.lang.python/msg/f1f10ced88c68c2d
    if n <= 2:
        return []
    sieve = list(range(3, n, 2))
    top = len(sieve)
    for si in sieve:
        if si:
            bottom = (si * si - 3) // 2
            if bottom >= top:
                break
            sieve[bottom::si] = [0] * -((bottom - top) // si)
    return [2] + [el for el in sieve if el]


def sieve_of_atkin(end):
    """return a list of all the prime numbers <end using the Sieve of Atkin."""
    # Code by Steve Krenzel, <Sgk284@gmail.com>, improved
    # Code: https://web.archive.org/web/20080324064651/http://krenzel.info/?p=83
    # Info: http://en.wikipedia.org/wiki/Sieve_of_Atkin
    assert end > 0
    lng = (end - 1) // 2
    sieve = [False] * (lng + 1)

    x_max, x2, xd = int(sqrt((end - 1) / 4.0)), 0, 4
    for xd in range(4, 8 * x_max + 2, 8):
        x2 += xd
        y_max = int(sqrt(end - x2))
        n, n_diff = x2 + y_max * y_max, (y_max << 1) - 1
        if not (n & 1):
            n -= n_diff
            n_diff -= 2
        for d in range((n_diff - 1) << 1, -1, -8):
            m = n % 12
            if m == 1 or m == 5:
                m = n >> 1
                sieve[m] = not sieve[m]
            n -= d

    x_max, x2, xd = int(sqrt((end - 1) / 3.0)), 0, 3
    for xd in range(3, 6 * x_max + 2, 6):
        x2 += xd
        y_max = int(sqrt(end - x2))
        n, n_diff = x2 + y_max * y_max, (y_max << 1) - 1
        if not (n & 1):
            n -= n_diff
            n_diff -= 2
        for d in range((n_diff - 1) << 1, -1, -8):
            if n % 12 == 7:
                m = n >> 1
                sieve[m] = not sieve[m]
            n -= d

    x_max, y_min, x2, xd = int((2 + sqrt(4 - 8 * (1 - end))) / 4), -1, 0, 3
    for x in range(1, x_max + 1):
        x2 += xd
        xd += 6
        if x2 >= end:
            y_min = (((int(ceil(sqrt(x2 - end))) - 1) << 1) - 2) << 1
        n, n_diff = ((x * x + x) << 1) - 1, (((x - 1) << 1) - 2) << 1
        for d in range(n_diff, y_min, -8):
            if n % 12 == 11:
                m = n >> 1
                sieve[m] = not sieve[m]
            n += d

    primes = [2, 3]
    if end <= 3:
        return primes[: max(0, end - 2)]

    for n in range(5 >> 1, (int(sqrt(end)) + 1) >> 1):
        if sieve[n]:
            primes.append((n << 1) + 1)
            aux = (n << 1) + 1
            aux *= aux
            for k in range(aux, end, 2 * aux):
                sieve[k >> 1] = False

    s = int(sqrt(end)) + 1
    if s % 2 == 0:
        s += 1
    primes.extend([i for i in range(s, end, 2) if sieve[i >> 1]])

    return primes


def ambi_sieve_plain(n):
    s = list(range(3, n, 2))
    for m in range(3, int(n ** 0.5) + 1, 2):
        if s[(m - 3) // 2]:
            for t in range((m * m - 3) // 2, (n >> 1) - 1, m):
                s[t] = 0
    return [2] + [t for t in s if t > 0]


def sundaram3(max_n):
    # /programming/2068372/fastest-way-to-list-all-primes-below-n-in-python/2073279#2073279
    numbers = range(3, max_n + 1, 2)
    half = (max_n) // 2
    initial = 4

    for step in range(3, max_n + 1, 2):
        for i in range(initial, half, step):
            numbers[i - 1] = 0
        initial += 2 * (step + 1)

        if initial > half:
            return [2] + filter(None, numbers)


# Using Numpy:
def ambi_sieve(n):
    # http://tommih.blogspot.com/2009/04/fast-prime-number-generator.html
    s = np.arange(3, n, 2)
    for m in range(3, int(n ** 0.5) + 1, 2):
        if s[(m - 3) // 2]:
            s[(m * m - 3) // 2::m] = 0
    return np.r_[2, s[s > 0]]


def primesfrom3to(n):
    # /programming/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    """ Returns an array of primes, p < n """
    assert n >= 2
    sieve = np.ones(n // 2, dtype=np.bool)
    for i in range(3, int(n ** 0.5) + 1, 2):
        if sieve[i // 2]:
            sieve[i * i // 2::i] = False
    return np.r_[2, 2 * np.nonzero(sieve)[0][1::] + 1]


def primesfrom2to(n):
    # /programming/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    """ Input n>=6, Returns an array of primes, 2 <= p < n """
    assert n >= 6
    sieve = np.ones(n // 3 + (n % 6 == 2), dtype=np.bool)
    sieve[0] = False
    for i in range(int(n ** 0.5) // 3 + 1):
        if sieve[i]:
            k = 3 * i + 1 | 1
            sieve[((k * k) // 3)::2 * k] = False
            sieve[(k * k + 4 * k - 2 * k * (i & 1)) // 3::2 * k] = False
    return np.r_[2, 3, ((3 * np.nonzero(sieve)[0] + 1) | 1)]


def sympy_sieve(n):
    return list(sympy.sieve.primerange(1, n))


perfplot.save(
    "prime.png",
    setup=lambda n: n,
    kernels=[
        rwh_primes,
        rwh_primes1,
        rwh_primes2,
        sieve_wheel_30,
        sieve_of_eratosthenes,
        sieve_of_atkin,
        # ambi_sieve_plain,
        # sundaram3,
        ambi_sieve,
        primesfrom3to,
        primesfrom2to,
        sympy_sieve,
    ],
    n_range=[2 ** k for k in range(3, 25)],
    logx=True,
    logy=True,
    xlabel="n",
)

0

Benim tahminim, tüm yollardan en hızlısı kodunuzdaki asalları zor kodlamaktır.

Öyleyse neden sadece tüm numaraları kablolu olarak bağlanmış başka bir kaynak dosyası oluşturan yavaş bir komut dosyası yazmıyorsunuz ve gerçek programınızı çalıştırdığınızda bu kaynak dosyayı içe aktarmıyorsunuz.

Tabii ki, bu sadece derleme zamanında N'nin üst sınırını biliyorsanız çalışır, ancak bu nedenle (neredeyse) tüm proje Euler problemleri için geçerlidir.

 

PS: Sabit kablolu primler ile kaynağı ayrıştırma ilk başta onları işlemekten daha yavaş olsa da yanlış olabilirim, ama bildiğim kadarıyla Python derlenmiş .pycdosyalardan çalışıyor, bu yüzden N'ye kadar tüm primerlerle bir ikili dizi okumak kanlı olmalı bu durumda hızlı.


0

Rahatsız ettiğim için üzgünüm ama erat2 () algoritmasında ciddi bir kusura sahip.

Bir sonraki kompoziti ararken, yalnızca tek sayıları test etmemiz gerekir. q, p'nin her ikisi de tuhaftır; q + p eşittir ve test edilmesi gerekmez, ancak q + 2 * p her zaman tuhaftır. Bu, while döngüsü koşulundaki "çift eşit" testini ortadan kaldırır ve çalışma zamanının yaklaşık% 30'unu kaydeder.

Biz oradayken: zarif 'D.pop (q, None)' alma ve silme yöntemi yerine 'D: p = D [q], del D [q]' deki q, iki kat daha hızlı ! En azından makinemde (P3-1Ghz). Bu yüzden bu akıllı algoritmanın bu uygulamasını öneririm:

def erat3( ):
    from itertools import islice, count

    # q is the running integer that's checked for primeness.
    # yield 2 and no other even number thereafter
    yield 2
    D = {}
    # no need to mark D[4] as we will test odd numbers only
    for q in islice(count(3),0,None,2):
        if q in D:                  #  is composite
            p = D[q]
            del D[q]
            # q is composite. p=D[q] is the first prime that
            # divides it. Since we've reached q, we no longer
            # need it in the map, but we'll mark the next
            # multiple of its witnesses to prepare for larger
            # numbers.
            x = q + p+p        # next odd(!) multiple
            while x in D:      # skip composites
                x += p+p
            D[x] = p
        else:                  # is prime
            # q is a new prime.
            # Yield it and mark its first multiple that isn't
            # already marked in previous iterations.
            D[q*q] = q
            yield q

dikteye ertelenen primler eklemek için (girişte bir asalin karesi görünene kadar) bkz. stackoverflow.com/a/10733621/849891 .
Ness Ness

0

Şimdiye kadar denediğim en hızlı yöntem Python yemek kitabıerat2 işlevine dayanıyor :

import itertools as it
def erat2a( ):
    D = {  }
    yield 2
    for q in it.islice(it.count(3), 0, None, 2):
        p = D.pop(q, None)
        if p is None:
            D[q*q] = q
            yield q
        else:
            x = q + 2*p
            while x in D:
                x += 2*p
            D[x] = p

Hızlandırmanın açıklaması için bu cevaba bakınız .


0

Partiye geç kalabilirim ama bunun için kendi kodumu eklemem gerekecek. Uzayda yaklaşık n / 2 kullanıyor çünkü çift sayıları depolamamız gerekmiyor ve ben de bitarray python modülünü kullanıyorum, bellek tüketimini daha da azaltıyor ve 1.000.000.000'a kadar tüm primerlerin hesaplanmasını sağlıyor

from bitarray import bitarray
def primes_to(n):
    size = n//2
    sieve = bitarray(size)
    sieve.setall(1)
    limit = int(n**0.5)
    for i in range(1,limit):
        if sieve[i]:
            val = 2*i+1
            sieve[(i+i*val)::val] = 0
    return [2] + [2*i+1 for i, v in enumerate(sieve) if v and i > 0]

python -m timeit -n10 -s "import euler" "euler.primes_to(1000000000)"
10 loops, best of 3: 46.5 sec per loop

Bu 64bit 2.4GHZ MAC OSX 10.8.3 üzerinde çalıştırıldı


1
bilinmeyen bir makine için bir zamanlama yayınlamak hiçbir şey söylemez. Burada kabul edilen cevap "psyco olmadan, n = 1000000 için, rwh_primes2 en hızlıydı" diyor. Dolayısıyla, bu kod için zamanlamalarınızı ve aynı makinede ve aynı zamanda 2, 4, 10 milyonda verirseniz, o zaman çok daha bilgilendirici olurdu.
Ness Ness

-1, Bu kod, C'de uygulanan bitarray'ın özel özelliklerine bağlıdır, bu yüzden işin çoğu dilim atamasında yerel kodda yapıldığından kod hızlıdır. Bitarray paket BOZMA bu 0/1 veya dilimin tüm unsurları Yanlış Gerçek / saf Python için standart davranışı görülmektedir, oysa tek mantıksal atama sağlar ki kesilebilir sekansları için (bir dizi üzerine endekslenmiş) uygun dilimleri için standart bir tanım buna izin vermemek ve yalnızca 0 atama değerine izin vermek, bu durumda sekans / dizideki tüm dilim öğelerinin del değeri olarak kabul edilir.
GordonBGood

devamı: Standart olmayan yerel kodu çağırmak karşılaştırılacak olsaydı, Kim Walisch'in primesieve'si gibi C koduna dayalı bir "fastprimes" dizi üreteci paketi de yazabilir ve dört milyar artı 32'deki tüm primerleri üretebiliriz. sıra üreteci tek bir çağrı ile sadece birkaç saniye içinde bit sayısı aralığı. Bağlantılı kod Eratosthenes'in elenmiş bir Eleme'sine dayandığından ve bu nedenle yalnızca birkaç on Kilobayt RAM kullandığından ve bir sekans üretilirse, bir liste depolaması gerekmeyeceğinden, neredeyse hiç bellek kullanmaz.
GordonBGood

0

Zamanla birkaç asal elek topladım. Bilgisayarımdaki en hızlı şudur:

from time import time
# 175 ms for all the primes up to the value 10**6
def primes_sieve(limit):
    a = [True] * limit
    a[0] = a[1] = False
    #a[2] = True
    for n in xrange(4, limit, 2):
        a[n] = False
    root_limit = int(limit**.5)+1
    for i in xrange(3,root_limit):
        if a[i]:
            for n in xrange(i*i, limit, 2*i):
                a[n] = False
    return a

LIMIT = 10**6
s=time()
primes = primes_sieve(LIMIT)
print time()-s

0

Bu soruya yavaş yanıt veriyorum ama eğlenceli bir egzersiz gibi görünüyordu. Hile olabilecek numpy kullanıyorum ve bu yöntemin en hızlı olduğundan şüpheliyim ama net olmalı. Yalnızca endekslerini referans alan bir Boolean dizisini eler ve tüm True değerlerinin indekslerinden asal sayılar çıkarır. Modulo gerekmez.

import numpy as np
def ajs_primes3a(upto):
    mat = np.ones((upto), dtype=bool)
    mat[0] = False
    mat[1] = False
    mat[4::2] = False
    for idx in range(3, int(upto ** 0.5)+1, 2):
        mat[idx*2::idx] = False
    return np.where(mat == True)[0]

yanlış, örneğin, ajs_primes3a(10)-> array([2, 3, 5, 7, 9]). 9asal değil
jfs

Yapmadığım bir kenar davası buldun - aferin! Sorun 'aralıktaki idx içindi (3, int (** 0,5'e kadar), 2):' ki aralıktaki idx için olmalı (3, int (** 0,5'e kadar + 1, 2): '). Teşekkürler ama şimdi çalışıyor.
Alan James Salmoni

Bunun nedeni, idx döngüsünün 15'e kadar olan vakalar için '05'e kadar çıkmasıydı. 16'dan itibaren iyi çalışıyor. Bu, test etmediğim bir dizi son durumdu. 1 eklenmesi, tüm sayılar için çalışması gerektiği anlamına gelir.
Alan James Salmoni

Şimdi çalışıyor gibi görünüyor. numpyBir dizi döndüren tabanlı çözümler arasında en yavaş olanıdır . Not: Eratosthenes uygulamasının gerçek bir eleği modulo kullanmaz - bundan bahsetmeye gerek yoktur. Bunun mat[idx*idx::idx]yerine kullanabilirsiniz mat[idx*2::idx]. Ve np.nonzero(mat)[0]yerine np.where(mat == True)[0].
jfs

Teşekkürler JF. Prime6 () 'a karşı test ettim ve prime6 () ele geçirildiğinde yaklaşık 250k'ye (IIRC) kadar daha hızlı bir sonuç aldım. primesfrom2to () daha hızlıydı. 20m'ye kadar, ajs_primes3a () 0.034744977951ms, prime6 () 0.0222899913788ms ve primesfrom2to () 0.0104751586914ms (aynı makine, aynı yük, 10 zamanlamanın en iyisini) aldı. Dürüst olmak gerekirse düşündüğümden daha iyi!
Alan James Salmoni

0

İşte python'un liste kavrayışlarını kullanarak asal sayılar (ancak en verimli değil) oluşturmak için ilginç bir teknik:

noprimes = [j for i in range(2, 8) for j in range(i*2, 50, i)]
primes = [x for x in range(2, 50) if x not in noprimes]

Örneği ve bazı açıklamaları burada bulabilirsiniz

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.