Dieses C17-Programm prüft Zahlen durch Probedivision und listet die Primzahlen von 1 bis zu einer oberen Grenze n einschließlich auf. Eine Primzahl ist eine ganze Zahl ab 2; bei einer Grenze von 0 oder 1 werden daher keine Primzahlen ausgegeben. Geben Sie genau eine ganze Dezimalzahl zwischen 0 und INT_MAX ein.
Code
| |
Kompilieren und Ausführungsbeispiel
Speichern Sie das Programm als primes.c. Führen Sie in einer Umgebung mit GCC zunächst gcc -std=c17 -Wall -Wextra -O2 primes.c -o primes und dann ./primes aus. Bei der Eingabe 30 erscheint nach einer Überschrift diese Zeile:
| |
Die Grenze 2 ergibt 2; 0 oder 1 ergibt eine leere Zeile. Eingelesen wird eine Textzeile mit höchstens 127 Bytes ohne das Zeilenumbruchzeichen. Leerraum am Anfang und Ende sowie ein führendes + sind erlaubt. Negative Werte, leere Zeilen, Text ohne gültige ganze Zahl, Werte außerhalb des Bereichs, zu lange Zeilen und Lesefehler führen zu einer Fehlermeldung und beenden das Programm. Nur die erste Zeile wird verarbeitet; weitere Zeilen werden nicht verwendet.
Funktionsweise von Test und Eingabeverarbeitung
isPrimeliefert für Werte bis einschließlich 1 falsch und für 2 und 3 wahr. Für andere Vielfache von 2 oder 3 liefert die Funktion falsch. Danach prüft sieiundi + 2füri = 5, 11, 17, .... Die möglichen Teiler haben die Form6k - 1oder6k + 1; sie sind keine Vielfachen von 6. Auch ist nicht jede Zahl dieser Formen eine Primzahl.- Jede zusammengesetzte Zahl hat einen Primteiler, der höchstens ihrer Quadratwurzel entspricht. Daher genügt die Prüfung, solange
i <= num / igilt. Bei positiven ganzen Zahlen erfasst dies denselben Bereich wiei * i <= num, vermeidet aber einen Überlauf der Multiplikation im Typint. Eine Quadratwurzelberechnung mit Gleitkommazahlen ist nicht nötig. printPrimesgibt bei einer Grenze unter 2 nur eine leere Zeile aus. Andernfalls gibt die Funktion zuerst 2 aus und prüft dann ungerade Kandidaten. Wenni > n - 2gilt, endet die Schleife vor der Addition. So läuft auch bei der GrenzeINT_MAXdas letztei += 2nicht über.readLimitliest mitfgets, prüft den Zeiger auf das Konvertierungsende undERANGEvonstrtolsowie den Bereich von 0 bisINT_MAX. Erst danach wird inintumgewandelt. Das Argument vonisspacewird zuvor inunsigned charumgewandelt. Wer den Rückgabewert vonscanf("%d", &n)ignoriert, riskiert nach fehlgeschlagener Eingabe die Verwendung eines nicht initialisiertenn. Man darf ebenfalls nicht voraussetzen, dass ein Konvertierungsergebnis außerhalb desint-Bereichs lediglich zu einem gewöhnlichen Konvertierungsfehler führt.
Einsatzbereich
INT_MAX hängt von der Implementierung ab. Bei einem 32-Bit-int beträgt der Wert 2,147,483,647; C schreibt ihn jedoch nicht für alle Implementierungen vor. Dass sich eine Grenze darstellen lässt, bedeutet nicht, dass sich alle Primzahlen bis dorthin schnell ausgeben lassen.
Diese Implementierung dient zum Lernen der Probedivision. Für eine einzelne Zahl ist die Anzahl der Divisionen nach oben durch einen zur Quadratwurzel proportionalen Wert beschränkt. Für die Auflistung aller Kandidaten ergibt sich als grobe obere Schranke O(n sqrt(n)) Divisionen. Dabei zählt eine Division als eine Operation; gemeint sind weder Bitkomplexität noch gemessene Laufzeit. Für große Intervalle bietet sich das Sieb des Eratosthenes an. Dies ist kein kryptografischer Primzahlgenerator. Zum Testen großer ganzer Zahlen siehe den Artikel zu Miller–Rabin.
Die Regeln zu Eingabefunktionen und Ganzzahlarithmetik stehen in den Abschnitten 6.5, 7.4, 7.21.6.2, 7.21.7.2 und 7.22.1.4 des C11-Komiteeentwurfs N1570 von WG14.
