Was ist der eleganteste Weg, um diese Funktion zu implementieren:
ArrayList generatePrimes(int n)
Diese Funktion generiert die ersten n
Primzahlen (edit: where n>1
) und gibt daher generatePrimes(5)
ein ArrayList
with zurück {2, 3, 5, 7, 11}
. (Ich mache das in C #, aber ich bin zufrieden mit einer Java-Implementierung - oder einer anderen ähnlichen Sprache (also nicht Haskell)).
Ich weiß, wie man diese Funktion schreibt, aber als ich sie letzte Nacht gemacht habe, war sie nicht so schön, wie ich es mir erhofft hatte. Folgendes habe ich mir ausgedacht:
ArrayList generatePrimes(int toGenerate)
{
ArrayList primes = new ArrayList();
primes.Add(2);
primes.Add(3);
while (primes.Count < toGenerate)
{
int nextPrime = (int)(primes[primes.Count - 1]) + 2;
while (true)
{
bool isPrime = true;
foreach (int n in primes)
{
if (nextPrime % n == 0)
{
isPrime = false;
break;
}
}
if (isPrime)
{
break;
}
else
{
nextPrime += 2;
}
}
primes.Add(nextPrime);
}
return primes;
}
Ich mache mir keine allzu großen Sorgen um die Geschwindigkeit, obwohl ich nicht möchte, dass sie offensichtlich ineffizient ist. Es macht mir nichts aus, welche Methode verwendet wird (naiv oder Sieb oder irgendetwas anderes), aber ich möchte, dass es ziemlich kurz und offensichtlich ist, wie es funktioniert.
Edit : Danke an alle, die geantwortet haben, obwohl viele meine eigentliche Frage nicht beantwortet haben. Um es noch einmal zu wiederholen, ich wollte einen schönen, sauberen Code, der eine Liste von Primzahlen generiert. Ich weiß bereits, wie man es auf verschiedene Arten macht, aber ich neige dazu, Code zu schreiben, der nicht so klar ist, wie er sein könnte. In diesem Thread wurden einige gute Optionen vorgeschlagen:
- Eine schönere Version von dem, was ich ursprünglich hatte (Peter Smit, jmservera und Rekreativc)
- Eine sehr saubere Umsetzung des Siebsosthenes (Sternenblau)
- Verwenden Sie Java
BigInteger
undnextProbablePrime
für sehr einfachen Code, obwohl ich mir nicht vorstellen kann, dass er besonders effizient ist (dfa). - Verwenden Sie LINQ, um die Liste der Primzahlen (Maghis) träge zu erstellen.
- Fügen Sie viele Primzahlen in eine Textdatei ein und lesen Sie sie bei Bedarf ein.
Bearbeiten 2 : Ich habe in C # einige der hier angegebenen Methoden und eine andere hier nicht erwähnte Methode implementiert . Sie alle finden die ersten n Primzahlen effektiv (und ich habe eine anständige Methode , um die Grenze für die Siebe zu finden).
nubBy (((>1).).gcd) [2..]
. Es bleiben nur Nicht-Duplikate unter den natürlichen Zahlen, beginnend mit 2, während jede Zahl, derengcd
mit einer der zuvor gefundenen Zahlen größer als 1 ist, als Duplikat betrachtet wird. Es ist sehr ineffizient und quadratisch in der Anzahl der produzierten Primzahlen. Aber es ist elegant .import Data.List.Ordered ; let { _Y g = g (_Y g) ; primes = 2 : _Y( (3:) . minus [5,7..] . unionAll . map (\p-> [p*p, p*p+p*2..]) ) }
aber das basiert natürlich ausschließlich auf Meinungen .Antworten:
Verwenden Sie die Schätzung
für die Anzahl der Primzahlen bis zu n, um eine Grenze zu finden, und verwenden Sie dann ein Sieb. Die Schätzung unterschätzt die Anzahl der Primzahlen bis zu n etwas, so dass das Sieb etwas größer als nötig ist, was in Ordnung ist.
Dies ist mein Standard-Java-Sieb, das die ersten Millionen Primzahlen in etwa einer Sekunde auf einem normalen Laptop berechnet:
quelle
i <= Math.sqrt(limit)
in der äußeren Schleife zu schleifen?BitSet
durch eine Klasse, die die Radfaktorisierung für 2, 3 und 5 implementiert, wird sie fast dreimal schneller.Vielen Dank an alle, die hilfreiche Antworten gegeben haben. Hier sind meine Implementierungen einiger verschiedener Methoden zum Finden der ersten n Primzahlen in C #. Die ersten beiden Methoden sind so ziemlich das, was hier gepostet wurde. (Die Namen der Poster stehen neben dem Titel.) Ich habe vor, irgendwann das Sieb von Atkin zu machen, obwohl ich vermute, dass es nicht ganz so einfach ist wie die Methoden hier derzeit. Wenn jemand eine Möglichkeit sieht, eine dieser Methoden zu verbessern, würde ich gerne wissen :-)
Standardmethode ( Peter Smit , jmservera , Rekreativc )
Die erste Primzahl ist 2. Fügen Sie diese zu einer Liste von Primzahlen hinzu. Die nächste Primzahl ist die nächste Zahl, die durch keine Zahl in dieser Liste gleichmäßig teilbar ist.
Dies wurde optimiert, indem nur die Teilbarkeit bis zur Quadratwurzel der getesteten Zahl getestet wurde. und indem nur ungerade Zahlen getestet werden. Dies kann durch nur Testen optimiert werden Zahlen der Form
6k+[1, 5]
, oder30k+[1, 7, 11, 13, 17, 19, 23, 29]
oder so weiter .Sieb von Eratosthenes ( Sternenblau )
Dies findet alle Primzahlen zu k . Um eine Liste der ersten n Primzahlen zu erstellen, müssen wir zuerst den Wert der n- ten Primzahl approximieren . Die folgende Methode, wie hier beschrieben , führt dies aus.
Sieb von Sundaram
Ich habe dieses Sieb erst kürzlich entdeckt, aber es kann ganz einfach implementiert werden. Meine Implementierung ist nicht so schnell wie das Sieb von Eratosthenes, aber deutlich schneller als die naive Methode.
quelle
i+j+2*i*j
was zu einer falschen Ausgabe führt.Ich habe eine alte Frage wiederbelebt, bin aber beim Spielen mit LINQ darüber gestolpert.
Dieser Code erfordert .NET4.0 oder .NET3.5 mit parallelen Erweiterungen
quelle
Du bist auf dem guten Weg.
Einige Kommentare
Primzahlen.Add (3); bewirkt, dass diese Funktion für number = 1 nicht funktioniert
Sie müssen die Division nicht mit Primzahlen testen, die größer sind als der Quadratwurzel der zu testenden Zahl.
Vorgeschlagener Code:
quelle
Sie sollten einen Blick auf wahrscheinliche Primzahlen werfen . Schauen Sie sich insbesondere Randomisierte Algorithmen und den Miller-Rabin-Primalitätstest an .
Der Vollständigkeit halber können Sie einfach java.math.BigInteger verwenden :
quelle
Auf keinen Fall effizient, aber vielleicht am lesbarsten:
mit:
In der Tat nur eine Variation einiger Beiträge hier mit schönerer Formatierung.
quelle
Copyrights 2009 von St.Wittum 13189 Berlin DEUTSCHLAND unter CC-BY-SA Lizenz https://creativecommons.org/licenses/by-sa/3.0/
Der einfachste, aber eleganteste Weg, ALLE PRIMEN zu berechnen, wäre dieser, aber dieser Weg ist langsam und die Speicherkosten sind für höhere Zahlen viel höher, weil die Fakultätsfunktion (!) Verwendet wird ... aber es zeigt eine Variation des Wilson-Theorems in einer Anwendung auf Generieren Sie alle Primzahlen mit einem in Python implementierten Algorithmus
quelle
Verwenden Sie eine erstklassige Zahlen Generator primes.txt zu erstellen und dann:
In diesem Fall verwende ich Int16 in der Methodensignatur, daher enthält meine Datei primes.txt Zahlen von 0 bis 32767. Wenn Sie dies auf Int32 oder Int64 erweitern möchten, kann Ihre Datei primes.txt erheblich größer sein.
quelle
Ich kann die folgende C # -Lösung anbieten. Es ist keineswegs schnell, aber es ist sehr klar, was es tut.
Ich habe alle Überprüfungen ausgelassen - wenn das Limit negativ oder kleiner als zwei ist (im Moment gibt die Methode immer mindestens zwei als Primzahl zurück). Aber das ist alles leicht zu beheben.
AKTUALISIEREN
Mit den folgenden zwei Erweiterungsmethoden
Sie können es wie folgt umschreiben.
Es ist weniger effizient (weil die Quadratwurzel ziemlich oft neu bewertet wird), aber es ist noch sauberer Code. Es ist möglich, den Code neu zu schreiben, um die Primzahlen träge aufzulisten, aber dies wird den Code ziemlich durcheinander bringen.
quelle
Hier ist eine Implementierung von Sieve of Eratosthenes in C #:
quelle
Mit demselben Algorithmus können Sie es etwas kürzer machen:
quelle
Ich weiß, dass Sie nach einer Nicht-Haskell-Lösung gefragt haben, aber ich füge diese hier ein, da sie sich auf die Frage bezieht, und auch Haskell ist für diese Art von Dingen wunderschön.
quelle
Ich habe eine einfache Eratosthenes-Implementierung in c # mit etwas LINQ geschrieben.
Leider bietet LINQ keine unendliche Folge von Ints, so dass Sie int.MaxValue :( verwenden müssen
Ich musste den Kandidaten sqrt in einem anonymen Typ zwischenspeichern, um zu vermeiden, dass er für jede zwischengespeicherte Primzahl berechnet wird (sieht etwas hässlich aus).
Ich verwende eine Liste früherer Primzahlen bis zum Quadrat des Kandidaten
und überprüfe jedes Int ab 2 dagegen
Hier ist der Code:
Eine weitere Optimierung besteht darin, zu vermeiden, dass gerade Zahlen überprüft werden, und nur 2 zurückzugeben, bevor die Liste erstellt wird. Auf diese Weise wird, wenn die aufrufende Methode nur nach 1 Primzahl fragt, das ganze Chaos vermieden:
quelle
Um es eleganter zu gestalten, sollten Sie Ihren IsPrime-Test in eine separate Methode umgestalten und die Schleifen und Inkremente außerhalb dieser Methode behandeln.
quelle
Ich habe es in Java mit einer von mir geschriebenen Funktionsbibliothek gemacht, aber da meine Bibliothek dieselben Konzepte wie Aufzählungen verwendet, bin ich sicher, dass der Code anpassbar ist:
quelle
Dies ist das eleganteste, an das ich kurzfristig denken kann.
Hoffe das hilft dir eine Idee zu geben. Ich bin sicher, dass dies optimiert werden kann, aber es sollte Ihnen eine Idee geben, wie Ihre Version eleganter gestaltet werden könnte.
BEARBEITEN: Wie in den Kommentaren erwähnt, gibt dieser Algorithmus tatsächlich falsche Werte für numberToGenerate <2 zurück. Ich möchte nur darauf hinweisen, dass ich nicht versucht habe, ihm eine großartige Methode zum Generieren von Primzahlen zu veröffentlichen (siehe Henrys Antwort darauf). Ich habe mürrisch darauf hingewiesen, wie seine Methode eleganter gestaltet werden könnte.
quelle
Mit der Stream-basierten Programmierung in Functional Java habe ich Folgendes gefunden. Der Typ
Natural
ist im Wesentlichen aBigInteger
> = 0.Jetzt haben Sie einen Wert, den Sie herumtragen können, der ein unendlicher Strom von Primzahlen ist. Sie können solche Dinge tun:
Eine Erklärung des Siebs:
Sie müssen die folgenden Importe haben:
quelle
Ich persönlich denke, dies ist eine ziemlich kurze und saubere (Java) Implementierung:
quelle
Probieren Sie diese LINQ-Abfrage aus. Sie generiert wie erwartet Primzahlen
quelle
quelle
Hier ist ein Python-Codebeispiel, das die Summe aller Primzahlen unter zwei Millionen ausgibt:
quelle
Die einfachste Methode ist das Ausprobieren: Sie versuchen, ob eine Zahl zwischen 2 und n-1 die Primzahl n Ihres Kandidaten teilt.
Die ersten Verknüpfungen sind natürlich a) Sie müssen nur ungerade Zahlen überprüfen und b) Sie müssen nur nach Teilern bis zu sqrt (n) suchen.
In Ihrem Fall, in dem Sie auch alle vorherigen Primzahlen im Prozess generieren, müssen Sie nur prüfen, ob eine der Primzahlen in Ihrer Liste bis zu sqrt (n) n teilt.
Sollte der schnellste sein, den du für dein Geld bekommen kannst :-)
edit
Ok, Code, du hast danach gefragt. Aber ich warne Sie :-), das ist ein 5-Minuten-Delphi-Code:
quelle
Um die ersten 100 Primzahlen herauszufinden, kann der folgende Java-Code berücksichtigt werden.
quelle
Ich habe dies durch die erste Lesung von "Sieve of Atkin" auf Wikki und einige frühere Überlegungen dazu erhalten - ich verbringe viel Zeit damit, von Grund auf neu zu programmieren, und werde völlig darauf konzentriert, dass Leute meine compilerähnliche, sehr dichte Codierung kritisieren style + Ich habe noch nicht einmal einen ersten Versuch unternommen, den Code auszuführen ... viele der Paradigmen, die ich gelernt habe, sind hier, lesen Sie einfach und weinen Sie, bekommen Sie, was Sie können.
Seien Sie absolut und absolut sicher, dass Sie dies alles wirklich testen, bevor Sie es verwenden. Zeigen Sie es auf keinen Fall jemandem - es dient zum Lesen und Überlegen der Ideen. Ich muss das Primality-Tool zum Laufen bringen, damit ich jedes Mal anfange, wenn ich etwas zum Laufen bringen muss.
Holen Sie sich eine saubere Kompilierung und entfernen Sie dann das, was defekt ist. Ich habe fast 108 Millionen Tastenanschläge mit verwendbarem Code, die dies auf diese Weise tun. Verwenden Sie, was Sie können.
Ich werde morgen an meiner Version arbeiten.
quelle
Versuchen Sie diesen Code.
Hier ist der Aspx-Code.
Ergebnisse: 10000 Primzahlen in weniger als einer Sekunde
100000 Primzahlen in 63 Sekunden
Screenshot der ersten 100 Primzahlen
quelle
isPrimeNubmer
implementieren tatsächlich die suboptimale Tril-Division; Die Asymptotyken verschlechtern sich auf etwa n ^ 2 (oder sogar darüber), wenn Sie versuchen, noch mehr Primzahlen zu erzeugen.