Es gibt Projekte, die mich als Assembler-Programmierer neugierig machten, wie diese wohl zu implementieren sind. So waren das biher die Ackermann-Funktion und die Berechnung Osterns. Dann fand ich im Netz einen Artikel über das Sieb des Eratosthenes: |
Aus [Wikipedia]:
Das Sieb des Eratosthenes ist ein Algorithmus zur Bestimmung einer Liste oder Tabelle aller Primzahlen kleiner oder gleich einer vorgegebenen Zahl.
Er ist nach dem griechischen Mathematiker Eratosthenes von Kyrene benannt.
Allerdings hat Eratosthenes, der im 3. Jahrhundert vor Christus lebte, das Verfahren nicht entdeckt, sondern nur die Bezeichnung „Sieb“ für das schon lange vor seiner Zeit bekannte Verfahren eingeführt.
Zunächst werden alle Zahlen 2, 3, 4,... bis zu einem frei wählbaren Maximalwert S aufgeschrieben.
Die zunächst unmarkierten Zahlen sind potentielle Primzahlen. Die kleinste unmarkierte Zahl ist immer eine Primzahl.
Nachdem eine Primzahl gefunden wurde, werden alle Vielfachen dieser Primzahl als zusammengesetzt markiert.
Man bestimmt die nächstgrößere nicht markierte Zahl.
Da sie kein Vielfaches von Zahlen kleiner als sie selbst ist (sonst wäre sie markiert worden), kann sie nur durch eins und sich selbst teilbar sein.
Folglich muss es sich um eine Primzahl handeln. Diese wird dementsprechend als Primzahl ausgegeben. Man streicht wieder alle Vielfachen und führt das Verfahren fort, bis man am Ende der Liste angekommen ist.
Im Verlauf des Verfahren werden alle Primzahlen ausgegeben.
Da mindestens ein Primfaktor einer zusammengesetzten Zahl immer kleiner gleich der Wurzel der Zahl sein muss, ist es ausreichend, nur die Vielfachen von Zahlen zu streichen, die kleiner oder gleich der Wurzel der Schranke S sind.
Ebenso genügt es beim Streichen der Vielfachen, mit dem Quadrat der Primzahl zu beginnen, da alle kleineren Vielfachen bereits markiert sind.
Das Verfahren beginnt also damit, die Vielfachen 4, 6, 8,... der kleinsten Primzahl 2 durchzustreichen.
Die nächste unmarkierte Zahl ist die nächstgrößere Primzahl, die 3. Anschließend werden deren Vielfache 9, 12, 15,... durchgestrichen, und so weiter.
Implementierung
Eine beispielhafte Implementierung des Algorithmus als Pseudocode:
|
An diesem Algorithmus fällt die Funktion sqrt(N) auf, die ich gemäß des Artikels
Tiny BASIC Square Root Routine umgesetzt habe.
|
const N = 10000 var gestrichen: array [2..N] of boolean // Initialisierung des Primzahlfeldes // Alle Zahlen im Feld sind zu Beginn nicht gestrichen for i = 2 to N do gestrichen[i] = false end // Siebe mit allen (Prim-) Zahlen i, wobei i der kleinste Primfaktor einer zusammengesetzten // Zahl j = i*k ist. Der kleinste Primfaktor einer zusammengesetzten Zahl j kann nicht größer // als die Wurzel von j <= n sein. for i = 2 to sqrt(N) do if not gestrichen[i] then // i ist prim, gib i aus... print i; ", "; // ...und streiche seine Vielfachen, beginnend mit i*i // (denn k*i mit k<i wurde schon als Vielfaches von k gestrichen) for j = i*i to N step i do gestrichen[j] = true end end if end // Gib die Primzahlen größer als Wurzel(n) aus - also die, die noch nicht gestrichen wurden for i = sqrt(N)+1 to N do if not gestrichen[i] then // i ist prim, gib i aus print i; ", "; end if end |
Das Ergebnis sind die Quelldateien SIEB1 und SQRT.
Später fand ich einen Algorithmus, der ohne die Wurzelberechnung auskommt — sogar ohne Division, was die Programmierung erheblich erleichtert: |
Eratosthenes(n) { a[1] := 0 for i := 2 to n do a[i] := 1 p := 2 while p² ≤ n do { j := p² while (j ≤ n) do { a[j] := 0 j := j+p } repeat p := p+1 until a[p] = 1 } return(a) } |
Das Ergebnis ist die Quelldatei SIEB2. hier mit der optionalen Eingabe des Maximalwertes. |