
(
Source de la figure )
Il est bien connu que le tamis d'Ératosthène (RE) est l'un des algorithmes les plus anciens apparus bien avant l'invention des ordinateurs. Par conséquent, vous pourriez penser qu'au cours des siècles, cet algorithme a été étudié de haut en bas et que rien ne peut y être ajouté. Si vous regardez Wikipedia, il y a une mer de références à des sources faisant autorité dans lesquelles vous pouvez facilement vous noyer. Par conséquent, j'ai été surpris lorsque j'ai découvert accidentellement l'autre jour que l'
option présentée comme optimale sur Wikipédia pouvait être considérablement optimisée.
C'était comme ça. Dans une discussion d'un article sur la programmation fonctionnelle (FP), il a posé une
question : comment écrire RE dans ce paradigme. Possédant plus qu'une maigre connaissance de la FA, je n'ose pas juger les réponses, mais d'autres participants à la discussion ont rejeté immédiatement certaines des solutions proposées, indiquant qu'au lieu de la complexité théorique
O(n log logn) (1)la mise en œuvre proposée aura une complexité de calcul
O(n2/ logn) (2)et qu'avec une telle complexité, vous ne pouvez pas attendre lorsque, par exemple, 10 millions de numéros sont triés. Je me suis intéressé et j'ai essayé d'implémenter la version optimale selon Wikipedia, en utilisant la programmation procédurale habituelle. Dans Delphi-7, j'ai obtenu le code suivant:
Listing 1program EratosthenesSieve;
RE est représenté par le tableau booléen tamis avec des valeurs inverses - si le nombre est premier, il est indiqué comme faux, ce qui réduit le nombre d'opérations de négation (pas) pendant le tamisage. Il y a 3 procédures dans le programme: initialisation du RE - init, calculs (criblage et barrage des nombres dans le RE) - calc, et impression des nombres premiers trouvés en conséquence - print, et le nombre de nombres trouvés est compté. J'attirerai particulièrement l'attention sur la sortie commentée des nombres premiers dans la procédure d'impression: pour les tests à N = 1000, le commentaire est supprimé.
Ici, dans la procédure de calcul, j'utilise la recommandation Wikipedia: pour le prochain nombre premier i, supprimez les nombres de l'ER
i2,i2+i,i2+2i,...
Ce programme a passé au crible un milliard de chiffres en 17,6 secondes. sur mon PC (processeur Intel Core i7 à 3,4 GHz).
Ayant réalisé ce programme, je me suis soudain souvenu des propriétés bien connues des
nombres pairs et impairs .
Lemme 1. 1) impair + impair = pair; 2) impair + pair = impair; 3) pair + pair = pair.Preuve1)
(2n+1)+(2m+1)=2n+2m+2 divisible par 2. TCD.
2)
(2n+1)+(2m)=2n+2m+1 non divisible par 2 sans reste. Chtd.
3)
(2n)+(2m)=2n+2m divisible par 2. TCD.
Lemme 2. Le carré d'un nombre impair est un nombre impair.Preuve. (2n+1)2=4n2+4n+1 non divisible par 2 sans reste. Chtd.
Remarque. Un nombre premier supérieur à 2 est impair.Par conséquent, vous ne pouvez supprimer que des nombres impairs:
i2,i2+2i,i2+4i,... (3)Mais vous devez d'abord barrer tous les nombres pairs. Cela se fait par une procédure d'initialisation init modifiée.
Listing 2 program EratosthenesSieve;
Ce programme a fonctionné pendant 9,9 secondes. - presque deux fois plus vite.
Pour évaluer la correspondance entre le fonctionnement du programme en temps réel et le fonctionnement théorique, j'ai suggéré que
dt=C∗O,
où
dt - durée de fonctionnement mesurée;
C - constant avec la dimension du temps;
O - évaluation théorique.
Calculé à partir d'ici
C évaluer (1) et (2). Pour
N=106 et moins
dt proche de zéro. Par conséquent, j'apporte les données sur le premier programme pour les grands
N.Comme nous le voyons, l'estimation (1) est beaucoup plus proche des résultats réels. Pour le deuxième programme, une image similaire est observée. Je doute beaucoup d'avoir découvert l'Amérique en utilisant la séquence (3) et je serai très reconnaissant du lien avec le travail où cette approche a été appliquée. Très probablement, les auteurs de Wikipédia eux-mêmes se sont noyés dans une mer d'informations sur la guerre électronique et ont raté ce travail.
PS Pour l'algorithme Wikipedia avec «runtime linéaire»,
voir