Dies ist der beste Algorithmus, den ich finden konnte.
def get_primes(n):
numbers = set(range(n, 1, -1))
primes = []
while numbers:
p = numbers.pop()
primes.append(p)
numbers.difference_update(set(range(p*2, n+1, p)))
return primes
>>> timeit.Timer(stmt='get_primes.get_primes(1000000)', setup='import get_primes').timeit(1)
1.1499958793645562
Kann es noch schneller gemacht werden?
Dieser Code weist einen Fehler auf: Da numbers
es sich um einen ungeordneten Satz handelt, gibt es keine Garantie dafür, dass numbers.pop()
die niedrigste Zahl aus dem Satz entfernt wird. Trotzdem funktioniert es (zumindest für mich) für einige Eingabenummern:
>>> sum(get_primes(2000000))
142913828922L
#That's the correct sum of all numbers below 2 million
>>> 529 in get_primes(1000)
False
>>> 529 in get_primes(530)
True
python
math
optimization
primes
jbochi
quelle
quelle
import antigravity
. Gibt es nicht so etwas wierequire 'prime'; Prime.take(10)
(Ruby)?Antworten:
Warnung: Die
timeit
Ergebnisse können aufgrund von Hardware- oder Python-Unterschieden variieren.Unten finden Sie ein Skript, das eine Reihe von Implementierungen vergleicht:
Vielen Dank an stephan für sieve_wheel_30 , um meine Aufmerksamkeit zu bringen. Der Kredit geht an Robert William Hanks für Primzahlen von 2 bis, Primzahlen von 3 bis, rwh_primes, rwh_primes1 und rwh_primes2.
Von den einfachen Python-Methoden, die mit psyco für n = 1000000 getestet wurden , war rwh_primes1 die am schnellsten getestete.
Von den einfachen Python-Methoden, die ohne Psyco für n = 1000000 getestet wurden , war rwh_primes2 die schnellste.
Von allen getesteten Methoden, die numpy für n = 1000000 zuließen, war primesfrom2to die am schnellsten getestete.
Die Timings wurden mit dem folgenden Befehl gemessen:
mit
{method}
durch jeden der Methodennamen ersetzt.primes.py:
Durch Ausführen des Skripts wird getestet, dass alle Implementierungen dasselbe Ergebnis liefern.
quelle
gmpy
- er unterstützt Primzahlen über dienext_prime
Methode seinesmpz
Typs ziemlich gut .Schneller und speichertechnischer reiner Python-Code:
oder beginnend mit einem halben Sieb
Schneller und speichertechnischer Numpy-Code:
Eine schnellere Variante, die mit einem Drittel eines Siebs beginnt:
Eine (schwer zu codierende) reine Python-Version des obigen Codes wäre:
Leider übernimmt Pure-Python nicht die einfachere und schnellere Art der Zuweisung, und das Aufrufen
len()
innerhalb der Schleife wie in[False]*len(sieve[((k*k)//3)::2*k])
ist zu langsam. Also musste ich improvisieren, um Eingaben zu korrigieren (und mehr Mathe zu vermeiden) und extreme (und schmerzhafte) Mathe-Magie zu machen.Persönlich finde ich es schade, dass numpy (das so weit verbreitet ist) nicht Teil der Python-Standardbibliothek ist und dass die Verbesserungen in Syntax und Geschwindigkeit von Python-Entwicklern völlig übersehen werden.
quelle
bitarray
- wie hier verwendet (für das einfachste Hauptsiebprimesfrom2to()
sich die Teilung beim Gießen in der Klammer innerhalb der Klammern befinden?Es ist eine ziemlich saubere Probe aus dem Python - Kochbuch hier - die schnellste Version auf dieser URL vorgeschlagen ist:
das würde also geben
Beim Messen an der Shell-Eingabeaufforderung (wie ich es vorziehen würde) mit diesem Code in pri.py beobachte ich:
Es sieht also so aus, als ob die Kochbuchlösung doppelt so schnell ist.
quelle
Ich glaube, ich habe mit Sundarams Sieb den Rekord von Pure-Python gebrochen:
Vergleich:
quelle
None
anstelle der ursprünglichen Funktion funktioniert und sogar noch schneller ist alszero.__sub__
sundaram3(9)
es zurückkehren wird[2, 3, 5, 7, 9]
? Es scheint dies mit zahlreichen - vielleicht allen - ungeraden Zahlen zu tun (auch wenn sie keine Primzahlen sind)Der Algorithmus ist schnell, hat aber einen schwerwiegenden Fehler:
Sie gehen davon aus, dass
numbers.pop()
dies die kleinste Zahl im Satz zurückgeben würde, dies ist jedoch überhaupt nicht garantiert. Mengen sind ungeordnet undpop()
entfernen und geben ein beliebiges Element zurück, sodass es nicht verwendet werden kann, um die nächste Primzahl aus den verbleibenden Zahlen auszuwählen.quelle
Für eine wirklich schnellste Lösung mit ausreichend großem N wäre es, eine vorberechnete Liste von Primzahlen herunterzuladen , als Tupel zu speichern und Folgendes zu tun:
Wenn
N > primes[-1]
nur dann mehr Primzahlen berechnet werden und die neue Liste in Ihrem Code gespeichert wird, ist sie beim nächsten Mal genauso schnell.Denken Sie immer über den Tellerrand hinaus.
quelle
Wenn Sie das Rad nicht neu erfinden möchten, können Sie die symbolische Mathematikbibliothek sympy installieren (ja, es ist Python 3-kompatibel).
Und verwenden Sie die Primerange- Funktion
quelle
Wenn Sie itertools akzeptieren, aber nicht numpy, finden Sie hier eine Anpassung von rwh_primes2 für Python 3, die auf meinem Computer etwa doppelt so schnell ausgeführt wird. Die einzige wesentliche Änderung besteht darin, ein Bytearray anstelle einer Liste für den Booleschen Wert zu verwenden und die Komprimierung anstelle eines Listenverständnisses zu verwenden, um die endgültige Liste zu erstellen. (Ich würde dies als Kommentar wie moarningsun hinzufügen, wenn ich könnte.)
Vergleiche:
und
quelle
Es ist lehrreich, Ihren eigenen Prime-Finding-Code zu schreiben, aber es ist auch nützlich, eine schnelle, zuverlässige Bibliothek zur Hand zu haben. Ich habe einen Wrapper um das Primesieve der C ++ - Bibliothek geschrieben , der Primesieve-Python heißt
Versuch es
pip install primesieve
Ich wäre gespannt auf die Geschwindigkeit im Vergleich.
quelle
count_primes
Funktion viel schneller alsgenerate_primes
Hier sind zwei aktualisierte (reine Python 3.6) Versionen einer der schnellsten Funktionen:
quelle
Eine deterministische Implementierung des Miller-Rabin-Primalitätstests unter der Annahme, dass N <9.080.191 ist
Laut dem Artikel auf Wikipedia ( http://en.wikipedia.org/wiki/Miller–Rabin_primality_test ) reicht es aus, N <9.080.191 auf a = 2,3,37 zu testen, und 73 reicht aus, um zu entscheiden, ob N zusammengesetzt ist oder nicht.
Und ich habe den Quellcode aus der probabilistischen Implementierung des ursprünglichen Miller-Rabin-Tests angepasst, der hier zu finden ist: http://en.literateprograms.org/Miller-Rabin_primality_test_(Python)
quelle
Wenn Sie die Kontrolle über N haben, können Sie alle Primzahlen am schnellsten auflisten, indem Sie sie vorberechnen. Ernsthaft. Precomputing ist eine Möglichkeit, die Optimierung zu übersehen.
quelle
Hier ist der Code, den ich normalerweise zum Generieren von Primzahlen in Python verwende:
Es kann nicht mit den hier veröffentlichten schnelleren Lösungen mithalten, aber es ist zumindest reine Python.
Vielen Dank für die Veröffentlichung dieser Frage. Ich habe heute wirklich viel gelernt.
quelle
Für den schnellsten Code ist die Numpy-Lösung die beste. Aus rein akademischen Gründen veröffentliche ich jedoch meine reine Python-Version, die etwas weniger als 50% schneller ist als die oben veröffentlichte Kochbuchversion. Da ich die gesamte Liste im Speicher erstelle, benötigen Sie genügend Speicherplatz, um alles aufzunehmen, aber es scheint ziemlich gut zu skalieren.
Und die Ergebnisse:
quelle
Eine etwas andere Implementierung eines halben Siebs mit Numpy:
http://rebrained.com/?p=458
Kann jemand dies mit den anderen Timings vergleichen? Auf meiner Maschine scheint es ziemlich vergleichbar mit dem anderen Numpy-Halbsieb zu sein.
quelle
upto=10**6
:primesfrom2to()
- 7 ms;prime6()
- 12 ms ideone.com/oDg2YEs ist alles geschrieben und getestet. Das Rad muss also nicht neu erfunden werden.
gibt uns einen Rekord von 12,2 ms !
Wenn dies nicht schnell genug ist, können Sie PyPy ausprobieren:
was in ... resultiert:
Die Antwort mit 247 Up-Votes listet 15,9 ms für die beste Lösung auf. Vergleichen Sie das !!!
quelle
Ich habe einige Funktionen von unutbu getestet und sie mit hungrigen Millionen berechnet
Die Gewinner sind die Funktionen, die die Numpy-Bibliothek verwenden.
Hinweis : Es wäre auch interessant, einen Speicherauslastungstest durchzuführen :)
Beispielcode
Vollständiger Code in meinem Github-Repository
quelle
Für Python 3
quelle
Schnellstes Hauptsieb in Pure Python :
Ich habe Sieb of Eratosthenes für Geschwindigkeit und Gedächtnis optimiert .
Benchmark
Ausgabe
quelle
Wenn Sie Python zum ersten Mal verwenden, scheinen einige der Methoden, die ich hier verwende, etwas umständlich zu sein. Ich habe gerade meinen C ++ - Code direkt in Python konvertiert und das ist es, was ich habe (wenn auch ein bisschen langsam in Python)
quelle
Ich weiß, dass der Wettbewerb seit einigen Jahren geschlossen ist. …
Dies ist jedoch mein Vorschlag für ein reines Python-Hauptsieb, bei dem die Vielfachen von 2, 3 und 5 weggelassen werden, indem geeignete Schritte ausgeführt werden, während das Sieb vorwärts verarbeitet wird. Trotzdem ist es für N <10 ^ 9 tatsächlich langsamer als für @Robert William Hanks überlegene Lösungen rwh_primes2 und rwh_primes1. Durch die Verwendung eines ctypes.c_ushort-Siebarrays über 1,5 * 10 ^ 8 ist es irgendwie an Speichergrenzen anpassbar.
10 ^ 6
$ python -mtimeit -s "importiere primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (1000000)" 10 Schleifen, am besten 3: 46,7 ms pro Schleife
10 ^ 7
$ python -mtimeit -s "importiere primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (10000000)" 10 Schleifen, am besten 3: 530 ms pro Schleife
10 ^ 8
$ python -mtimeit -s "importiere primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (100000000)" 10 Schleifen, am besten 3: 5,55 Sek. pro Schleife
10 ^ 9
$ python -mtimeit -s "importiere primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (1000000000)" 10 Schleifen, am besten 3: 61,2 Sekunden pro Schleife
Sie können den folgenden Code in ubuntus primeSieveSpeedComp kopieren, um diese Tests zu überprüfen.
quelle
Hier ist eine numpy-Version von Sieve of Eratosthenes, die sowohl eine gute Komplexität (niedriger als das Sortieren eines Arrays der Länge n) als auch eine Vektorisierung aufweist. Im Vergleich zu @unutbu mal ist dies genauso schnell wie die Pakete mit 46 Mikrosekunden, um alle Primzahlen unter einer Million zu finden.
Timings:
quelle
Ich habe einen Großteil des Codes für Python 3 aktualisiert und ihn auf perfplot (ein Projekt von mir) geworfen, um zu sehen, welcher tatsächlich am schnellsten ist. Es stellt sich heraus, dass für große
n
,primesfrom{2,3}to
nehmen Sie den Kuchen:Code zur Reproduktion der Handlung:
quelle
Ich vermute, dass der schnellste Weg darin besteht, die Primzahlen in Ihrem Code hart zu codieren.
Warum also nicht einfach ein langsames Skript schreiben, das eine andere Quelldatei generiert, in der alle Zahlen fest verdrahtet sind, und diese Quelldatei dann importieren, wenn Sie Ihr eigentliches Programm ausführen?
Dies funktioniert natürlich nur, wenn Sie die Obergrenze von N zur Kompilierungszeit kennen, ist jedoch bei (fast) allen Projekt-Euler-Problemen der Fall.
PS: Ich könnte mich zwar irren, wenn das Parsen der Quelle mit fest verdrahteten Primzahlen langsamer ist als das Berechnen, aber soweit ich weiß, läuft Python aus kompilierten
.pyc
Dateien, daher sollte das Lesen eines binären Arrays mit allen Primzahlen bis zu N blutig sein schnell in diesem Fall.quelle
Tut mir leid, aber erat2 () hat einen schwerwiegenden Fehler im Algorithmus.
Bei der Suche nach dem nächsten Verbund müssen wir nur ungerade Zahlen testen. q, p beide sind ungerade; dann ist q + p gerade und muss nicht getestet werden, aber q + 2 * p ist immer ungerade. Dies eliminiert den "wenn gerade" -Test in der while-Schleifenbedingung und spart etwa 30% der Laufzeit.
Während wir gerade dabei sind: Verwenden Sie anstelle der eleganten Methode 'D.pop (q, None)' get and delete 'if q in D: p = D [q], del D [q]', was doppelt so schnell ist ! Zumindest auf meiner Maschine (P3-1Ghz). Daher schlage ich diese Implementierung dieses cleveren Algorithmus vor:
quelle
Die schnellste Methode, die ich bisher ausprobiert habe, basiert auf der Python-Kochbuchfunktion
erat2
:In dieser Antwort finden Sie eine Erklärung für die Beschleunigung.
quelle
Ich komme möglicherweise zu spät zur Party, muss aber dafür meinen eigenen Code hinzufügen. Es benötigt ungefähr n / 2 im Speicherplatz, da wir keine geraden Zahlen speichern müssen, und ich verwende auch das Bitarray-Python-Modul, um den Speicherverbrauch weiter drastisch zu reduzieren und die Berechnung aller Primzahlen bis zu 1.000.000.000 zu ermöglichen
Dies wurde auf einem 64-Bit-2,4-GHz-MAC OSX 10.8.3 ausgeführt
quelle
Ich habe im Laufe der Zeit mehrere Primzahlsiebe gesammelt. Das schnellste auf meinem Computer ist das Folgende:
quelle
Ich beantworte diese Frage nur langsam, aber es schien eine lustige Übung zu sein. Ich benutze Numpy, was betrügen könnte und ich bezweifle, dass diese Methode die schnellste ist, aber es sollte klar sein. Es siebt ein Boolesches Array, das sich nur auf seine Indizes bezieht, und ermittelt Primzahlen aus den Indizes aller True-Werte. Kein Modulo erforderlich.
quelle
ajs_primes3a(10)
->array([2, 3, 5, 7, 9])
.9
ist kein Primenumpy
basierten Lösungen, die ein Array zurückgeben. Hinweis: Keine echte Sieve of Eratosthenes-Implementierung verwendet Modulo - es muss nicht erwähnt werden. Sie könntenmat[idx*idx::idx]
anstelle von verwendenmat[idx*2::idx]
. Undnp.nonzero(mat)[0]
stattnp.where(mat == True)[0]
.Hier ist eine interessante Technik zum Generieren von Primzahlen (aber nicht die effizienteste) unter Verwendung des Listenverständnisses von Python:
Das Beispiel und einige Erklärungen finden Sie hier
quelle