Python >> Tutoriel Python >  >> Python

La méthode Python la plus rapide pour calculer tous les nombres premiers

Présentation

Le calcul des nombres premiers à partir d'une série de nombres donnée n'est peut-être pas un gros problème. Cependant, le calcul des nombres premiers de la manière la plus efficace en gardant à l'esprit la complexité temporelle et d'autres facteurs peut être un problème difficile. Après tout, l'un des critères majeurs d'un code efficace est son efficacité. Par conséquent, dans cet article, nous allons comparer et contraster les complexités de différents codes pour calculer tous les nombres premiers inférieurs à N , où N désigne un nombre arbitraire de valeurs dans la série donnée telle qu'entrée par l'utilisateur.

Exemple : Vous trouverez ci-dessous un exemple simple de ce qui va suivre dans cet article :

import time
start_time = time.time()
n = int(input("Enter the last range of the series: "))
for i in range(1,n+1):
  if i>1:
    for j in range(2,i):
        if(i % j==0):
            break
    else:
        print(i)
end_time = time.time()
print("Elapsed Time: " + str(end_time-start_time))

Sortie :

Enter the last range of the series: 10
2
3
5
7
Elapsed Time: 3.9661035537719727

Avertissement : Les méthodes utilisées dans le script ci-dessous sont purement basées sur le moins de temps nécessaire pour calculer les nombres premiers

Sans plus tarder, plongeons-nous dans les comparaisons et visualisons le résultat.

Comparaison de codes

Au lieu de comparer les codes un par un ce qui allongerait inutilement l'article, voici une liste de toutes les méthodes probables pour calculer des nombres premiers dans une plage donnée avec le moins de temps de calcul possible.

from sympy import sieve
import numpy
import itertools

izip = itertools.zip_longest
chain = itertools.chain.from_iterable
compress = itertools.compress
import time


def method1(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]]


def method2(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]]


def method3(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)]


def method4(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]]


def method5(n):
    primes = list(sieve.primerange(1, n))
    return primes


def method6(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


m1_start = time.time()
method1(10 ** 6)
m1_end = time.time()
m1_et = m1_end - m1_start
print("Method 1 Elapsed time: " + str(m1_end - m1_start))

m2_start = time.time()
method2(10 ** 7)
m2_end = time.time()
m2_et = m2_end - m2_start
print("Method 2 Elapsed time: " + str(m2_end - m2_start))

m3_start = time.time()
method3(10 ** 7)
m3_end = time.time()
m3_et = m3_end - m3_start
print("Method 3 Elapsed time: " + str(m3_end - m3_start))

m4_start = time.time()
method4(10 ** 7)
m4_end = time.time()
m4_et = m4_end - m4_start
print("Method 4 Elapsed time: " + str(m4_end - m4_start))

m5_start = time.time()
method5(10 ** 7)
m5_end = time.time()
m5_et = m5_end - m5_start
print("Method 5 Elapsed time: " + str(m5_end - m5_start))

m6_start = time.time()
method6(10 ** 7)
m6_end = time.time()
m6_et = m6_end - m6_start
print("Method 6 Elapsed time: " + str(m6_end - m6_start))

Sortie :

Method 1 Elapsed time: 0.06881570816040039
Method 2 Elapsed time: 0.9155552387237549
Method 3 Elapsed time: 0.045876264572143555
Method 4 Elapsed time: 0.6512553691864014
Method 5 Elapsed time: 7.0082621574401855
Method 6 Elapsed time: 0.33211350440979004

D'après l'analyse ci-dessus, il est clair que la Méthode 3 prend le minimum temps pour calculer les nombres premiers Méthode 5 prend le maximum le temps de le faire. Pour comparer et contraster les différentes méthodes et le temps pris par chaque méthode, nous avons calculé le temps nécessaire pour calculer tous les nombres premiers dans la plage de 1 à 10 7 puis déduit notre conclusion. Par conséquent,

Notre gagnant :Méthode 3

Avis de non-responsabilité : Les valeurs du temps écoulé pris par chaque méthode telles que calculées par le time module peut varier en fonction du système/matériel utilisé et de la version de Python que vous utilisez.

Si vous utilisez toujours Python 2.x, vous pourriez avoir envie des méthodes suivantes indiquées ci-dessous :

from math import sqrt
import time


def method1(max_n):
    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)


def method2(n):
    """sieveOfEratosthenes(n): return the list of the primes < n."""
    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 method3(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 method4(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]]


m1_start = time.time()
method1(10 ** 6)
m1_end = time.time()
print("Method 1 Elapsed time: " + str(m1_end - m1_start))

m2_start = time.time()
method2(10 ** 6)
m2_end = time.time()
print("Method 2 Elapsed time: " + str(m2_end - m2_start))

m3_start = time.time()
method3(10 ** 6)
m3_end = time.time()
print("Method 3 Elapsed time: " + str(m3_end - m3_start))

m4_start = time.time()
method4(10 ** 6)
m4_end = time.time()
print("Method 4 Elapsed time: " + str(m4_end - m4_start))

Sortie :

Method 1 Elapsed time: 0.891271114349
Method 2 Elapsed time: 0.178880214691
Method 3 Elapsed time: 0.526117086411
Method 4 Elapsed time: 0.29536986351

Comparaison graphique

Considérant que l'extrait ci-dessus est écrit dans un fichier avec le nom plot.py , voici une analyse graphique des temps mis par chaque méthode pour calculer tous les nombres premiers inférieurs à N. Le code ci-dessous est utilisé pour tracer le bar-graph pour comparer les différentes méthodes utilisées pour calculer les nombres premiers

import plot
import matplotlib.pyplot as plt
import numpy as np

method = ['Method 1', 'Method 2', 'Method 3', 'Method 4', 'Method 5', 'Method 6']
et = [plot.m1_et, plot.m2_et, plot.m3_et, plot.m4_et, plot.m5_et, plot.m6_et]
c = ["red", "green", "orange", "blue", "black", "purple"]
ypos = np.arange(len(method))
plt.xticks(ypos, method)
plt.bar(ypos, et, 0.4, color=c)
plt.title("Time To Compute Primes")
plt.xlabel("Methods")
plt.ylabel("Elapsed Time (seconds)")
plt.show()

Tracé/Graphique Sortie :

❖ Vous trouverez ci-dessous une autre comparaison graphique utilisant un graphique linéaire en pointillés qui compare le temps pris par chaque méthode :

Sortie :

Le code pour générer le graphique ci-dessus est donné ci-dessous (Le code contenant les principales méthodes a été mentionné ci-dessus. Nous considérons qu'il est présent dans un fichier plot.py, puis nous l'importons dans notre fichier de classe principal pour tracer le graphique.)

import plot
import matplotlib.pyplot as plt
import numpy as np
method = ['Method 1', 'Method 2', 'Method 3', 'Method 4', 'Method 5', 'Method 6']
et = [plot.m1_et, plot.m2_et, plot.m3_et, plot.m4_et, plot.m5_et, plot.m6_et]
ypos = np.arange(len(method))
plt.xticks(ypos, method)
plt.plot(ypos, et, color='green', linestyle='dashed', linewidth = 3,
         marker='o', markerfacecolor='blue', markersize=12)
plt.title("Time To Compute Primes")
plt.xlabel("Methods")
plt.ylabel("Elapsed Time (seconds)")
plt.show()

Conclusion

Dans cet article, nous avons comparé plusieurs méthodes et trouvé la meilleure méthode en termes de temps minimum nécessaire pour calculer tous les nombres premiers

J'espère que vous avez apprécié l'article, veuillez vous abonner et rester à l'écoute pour des articles et des contenus plus intéressants comme celui-ci.

Référence : https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n


Prochain article