Ich habe einen reinen Python 2 Primzahlengenerator hier gefunden, in einem Kommentar von Willy Good, der schneller ist als rwh2_primes.
def primes235(limit):
yield 2; yield 3; yield 5
if limit < 7: return
modPrms = [7,11,13,17,19,23,29,31]
gaps = [4,2,4,2,4,6,2,6,4,2,4,2,4,6,2,6] # 2 loops for overflow
ndxs = [0,0,0,0,1,1,2,2,2,2,3,3,4,4,4,4,5,5,5,5,5,5,6,6,7,7,7,7,7,7]
lmtbf = (limit + 23) // 30 * 8 - 1 # integral number of wheels rounded up
lmtsqrt = (int(limit ** 0.5) - 7)
lmtsqrt = lmtsqrt // 30 * 8 + ndxs[lmtsqrt % 30] # round down on the wheel
buf = [True] * (lmtbf + 1)
for i in xrange(lmtsqrt + 1):
if buf[i]:
ci = i & 7; p = 30 * (i >> 3) + modPrms[ci]
s = p * p - 7; p8 = p << 3
for j in range(8):
c = s // 30 * 8 + ndxs[s % 30]
buf[c::p8] = [False] * ((lmtbf - c) // p8 + 1)
s += p * gaps[ci]; ci += 1
for i in xrange(lmtbf - 6 + (ndxs[(limit - 7) % 30])): # adjust for extras
if buf[i]: yield (30 * (i >> 3) + modPrms[i & 7])
Meine Ergebnisse:
$ time ./prime_rwh2.py 1e8
5761455 gefundene Primzahlen < 1e8
real 0m3.201s
user 0m2.609s
sys 0m0.578s
$ time ./prime_wheel.py 1e8
5761455 gefundene Primzahlen < 1e8
real 0m2.710s
user 0m2.469s
sys 0m0.219s
...auf meinem aktuellen Mittelklasse-Laptop (i5 8265U 1,6 GHz) mit Ubuntu auf Win 10.
Das ist ein Modulo-30-Radsieb, das Vielfache von 2, 3 und 5 überspringt. Es funktioniert für mich bis etwa 2,5e9 gut, wenn mein Laptop anfängt, viel Arbeitsspeicher zu verbrauchen und stark zu tauschen.
Ich mag Modulo 30, da es nur 8 Reste gibt, die keine Vielfachen von 2, 3 oder 5 sind. Das ermöglicht die Verwendung von Verschiebungen und "&" für Multiplikation, Division und Modulo und sollte das Verpacken von Ergebnissen für ein Modulo-30-Rad in ein Byte ermöglichen. Ich habe Willys Code in ein segmentiertes Modulo-30-Radsieb umgewandelt, um das Thrashing für große N zu eliminieren, und es hier veröffentlicht.
Es gibt sogar eine schnellere Javascript-Version, die segmentiert ist und ein Modulo-210-Rad verwendet (keine Vielfachen von 2, 3, 5 oder 7) von @GordonBGood mit einer ausführlichen Erklärung, die für mich nützlich ist.
0 Stimmen
Der Code-Schnipsel ist viel schneller, wenn Zahlen wie Zahlen = set(range(n, 2, -2)) deklariert werden. Aber kann sundaram3 nicht schlagen. Danke für die Frage.
4 Stimmen
Es wäre schön, wenn es Python 3-Versionen der Funktionen in den Antworten geben könnte.
0 Stimmen
Sicher gibt es eine Bibliothek, um dies zu tun, damit wir nicht selbst programmieren müssen. Xkcd versprach, dass Python so einfach ist wie
import antigravity
. Gibt es nicht so etwas wierequire 'prime'; Prime.take(10)
(Ruby)?0 Stimmen
Beachten Sie, dass Sie kein Set als Argument an
difference_update
übergeben müssen. Sie können einfachnumbers.difference_update(xrange(p*2, N+1, p))
tun. Das wird zumindest ein paar Millisekunden von Ihrer Zeit abziehen.2 Stimmen
Ich vermute, dass eine Python-Anbindung an die C++-Bibliothek primesieve um Größenordnungen schneller wäre als all diese.
4 Stimmen
@ColonelPanic Wie es sich herausstellt, habe ich github.com/jaredks/pyprimesieve für Py3 aktualisiert und zu PyPi hinzugefügt. Es ist sicherlich schneller als diese, aber nicht um Größenordnungen - eher etwa ~5x schneller als die besten numpy-Versionen.
0 Stimmen
Ich kenne den Geschwindigkeitsvergleich zu den bereits hier aufgelisteten Antworten nicht, ich würde jedoch empfehlen, sich sagemath.org anzusehen. Es handelt sich um ein Python-Krypto-Framework, das viele integrierte Funktionen hat, um die Dinge zu tun, nach denen Sie suchen.
4 Stimmen
@ColonelPanic: Ich denke, es ist angemessen, alte Antworten zu bearbeiten, um anzugeben, dass sie gealtert sind, da dies sie zu einer nützlicheren Ressource macht. Wenn die "akzeptierte" Antwort nicht mehr die beste ist, könnte man vielleicht eine Notiz in die Frage einfügen mit einem Update von 2015, um die Leute auf die aktuell beste Methode hinzuweisen.
0 Stimmen
Ich kann nicht glauben, dass kein Moderator diese Frage gelöscht hat. Sie bittet um Verbesserung in der Geschwindigkeit eines Algorithmus, der zugegebenermaßen nicht korrekt ist. Grüße, Albert
0 Stimmen
from sympy import sieve; sieve.extend(N);
0 Stimmen
Hey, das ist wirklich schneller Code. Du hast recht, der Code funktioniert für
n =10000
nicht, danumber.pop()
nicht das kleinste Element als ungeordnetes auslöst. Thread