Entwickler-Ecke
Algorithmen, Optimierung und Assembler - "Programm schneller machen"
luckyluc - Di 13.01.09 16:13
Titel: "Programm schneller machen"
Hallo
ich habe ein Programm welches wenn man eine Zahl eingibt, bis zu dieser Zahl alle Primzahlen ausgibt.
Nun nöchte ich diese Programm optimierend.h so gestalten dass das programm die primzahlen noch schneller findet. außer dass man nur bis zur wurzel der zu prüfenden zahl, den teiler hochzählen muss fällt mir nicht anderes ein.
Vielleicht habt ihr noch eine Idee?
Hier folgen zwei Quellcodes (sind im Grunde genommen das gleich, die for schleife ist jedoch schneller als die repeat)
1)
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31:
| var Form1: TForm1; i,teiler, eing_zahl,zeile: Integer; primzahl: Boolean; implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject); begin zeile:= 0; eing_zahl:= StrToInt (Edit1.Text);
for i := 4 to eing_zahl do begin primzahl := true;
for teiler := 2 to Trunc(sqrt(i)) do if i mod teiler = 0 then primzahl:= false;
if primzahl = true then begin inc (zeile); StringGrid1.Cells[0,zeile] := IntToStr(i); StringGrid1.RowCount := StringGrid1.RowCount+1; end;
end;end; |
2)
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36:
| var Form1: TForm1; i,teiler, eing_zahl,zeile: Integer; primzahl: Boolean;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject); begin zeile:= 0; eing_zahl:= StrToInt (Edit1.Text);
for i := 4 to eing_zahl do begin primzahl := true;
teiler:= 2; repeat if i mod teiler = 0 then primzahl := false; inc (teiler); until teiler = i-1;
if primzahl = true then begin inc (zeile); StringGrid1.Cells[0,zeile] := IntToStr(i); StringGrid1.RowCount := StringGrid1.RowCount+1; end;
end;end; |
Danke !
Moderiert von
Narses: Topic aus Sonstiges (Delphi) verschoben am Di 13.01.2009 um 15:16
Jelly - Di 13.01.09 16:52
Merke dir jede gefundene Primzahl in einem Array, und prüfe alle weiteren Zahlen nur auf Divisionen durch bereits gefundene Primzahlen.
Bsp: Du hast 2, 3, 5, 7, 11, 13 bereits gefunden
Du testest gern 143
Nimm die Wurzel: = 11,96... Prüfe als Division aller Primzahlen bis 12. d.h. es reicht aus eine Test durch 2, 3, 5, 7, 11 und 13 durchzuführen.
Ergibt eine der Divisionen 0, so ist die Zahl 143 KEINE Primzahl.
Ausserdem: Es hilft die Schleife abzubrechen, wenn einmal eine Division 0 ergibt. Du durchläufst das Testen jedoch noch weiter. Breche ab und teste die nächste Zahl.
Ums noch schneller zu machen. Vor vorneweg ist schon mal jede 2. Zahl keine Primzahl. Also alle geraden Zahlen brauchst du erst gar nicht testen (ausser 2).
jfheins - Di 13.01.09 17:28
Jelly hat folgendes geschrieben : |
Merke dir jede gefundene Primzahl in einem Array, und prüfe alle weiteren Zahlen nur auf Divisionen durch bereits gefundene Primzahlen.
Bsp: Du hast 2, 3, 5, 7, 11, 13 bereits gefunden
Du testest gern 143
Nimm die Wurzel: = 11,96... Prüfe als Division aller Primzahlen bis 12. d.h. es reicht aus eine Test durch 2, 3, 5, 7, 11 und 13 durchzuführen.
Ergibt eine der Divisionen 0, so ist die Zahl 143 KEINE Primzahl.
Ausserdem: Es hilft die Schleife abzubrechen, wenn einmal eine Division 0 ergibt. Du durchläufst das Testen jedoch noch weiter. Breche ab und teste die nächste Zahl.
Ums noch schneller zu machen. Vor vorneweg ist schon mal jede 2. Zahl keine Primzahl. Also alle geraden Zahlen brauchst du erst gar nicht testen (ausser 2). |
So ähnlich funktioniert das Sieb des Eratosthenes ;)
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49:
| var Form1: TForm1; implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject); var eing_zahl, zahl, i, limit: Integer; zahlen: Array of Boolean; begin
eing_zahl:= StrToInt (Edit1.Text);
limit := Trunc(sqrt(eing_zahl))
setlength(zahlen, eing_zahl + 1);
zahlen[0] := false; zahlen[1] := false; zahlen[2] := true; for i := 3 to eing_zahl do zahlen[i] := (i mod 2) = 1;
zahl := 2;
while zahl <= limit do begin inc(zahl);
if not zahlen[zahl] then continue;
i := zahl * 2; while i <= eing_zahl do begin zahlen[i] := false; i := i + zahl; end; end;
for i := 3 to eing_zahl do if zahlen[i] then Memo1.Lines.Add(inttostr(i) + ' ist prim!');
end; |
Am Ende ist zahlen[x] wahr für jede Primzahl und falsch für jede nicht-Primzahl im Bereich ;)
platzwart - Di 13.01.09 20:32
Primzahlen (>3) sind immer in der Form von 6n+/-1
Boldar - Di 13.01.09 21:44
Wirklich? Ist das bewiesen?
Hidden - Di 13.01.09 21:52
Hi :)
Wenn du zu 6n 3 addierst/subtrahierst, kommst du auf eine durch drei teilbare zahl => nicht prim
+- 2 => durch 2 teilbar
und noch +-0 => durch 3 und 2. Es verbleiben also nurnoch +-1.
aber diese Einschränkung kann man doch beliebig weiterspinnen, indem man stets die Vielfachen de nächsten Primzahl wegnimmt ;) . Die Formel hier liefert ja einfach nur alle Zahlen, die weder durch 3, noch durch 2 teilbar sind.
mfG,
JayEff - Mi 14.01.09 00:23
Boldar hat folgendes geschrieben : |
Wirklich? Ist das bewiesen? |
Leicht zu beweisen:
Ein Freund von mir hat folgendes geschrieben: |
Also - überleg erstmal - sei p > 3 eine Primzahl. Kann sie dann gerade sein? - Natürlich nicht.
Jede ganze Zahl ist von der Form 6x + i (wobei i die Werte -1,0,1,2,3,4 durchläuft)
Als Primzahl kann sie nicht von der Form 6x + 0, 6x + 2, 6x + 4 sein, denn dann wäre sie durch zwei teilbar.
Wäre sie von der Form 6x + 3 = 3(2x + 1), dann wäre sie durch 3 teilbar.
Bleibt also nur 1 und -1 übrig.
|
:zustimm:
Narses - Mi 14.01.09 00:25
Moin!
Bitte ändere den Titel des Topics, da er wenig über das eigentlich Thema verrät. Hier der entsprechende Absatz aus den
Richtlinien [
http://www.entwickler-ecke.de/richtlinien.html]:
1.2 Beiträge: |
Bitte formuliere den Betreff Deiner Beiträge so, dass andere Mitglieder anhand dieser bereits das eigentliche Thema festmachen können. Beiträge wie etwa "Eine Anfängerfrage" oder "Weiß jemand, wie das geht?" lassen den Leser im Unklaren darüber, was das Thema der Diskussion ist.[...] |
Einfach oben bei Deinem ersten Beitrag auf

oder

klicken und den Titel ändern. Danke Dir!
cu
Narses
Horst_H - Mi 14.01.09 02:17
Hallo,
heute habe mal eine Uraltversoin von Anfang 2001 ausgegraben:
wheel-sieving (Bei
http://www.devalco.de Stempel-Verfahren ).
Ein Stempel der Länge 2x3x5 = 30 (=5# wie 5! nur mit den ersten Primzahlen bis 5 ) hat nur noch (2-1)x(3-1)x(5-1) = 8 Erhebungen(beim Rad Zähne)[1,7,11,13,17,19,23,29] [31,37,..59] , was die Zahlen, die teilerfremd zu 2,3,5 sind darstellt.
Man hat jetzt nur noch 8/30 = 0.2666 aller Zahlen zu betrachten, weil die anderen garantiert durch 2,3,5 teilbar sind.
Jetzt braucht man nur 8 Bit um die 30 abzubilden muss aber eine Umrechnung vornehmen um aus der Zahl die Position im Bitfeld zu bestimmen und umgekehrt, welche Zahl repräsentiert ein bestimmtes gesetztes Bit.
Das kann man nicht nur 2,3,5 , sondern allgemein machen. ( Das gab eine paar neue Knoten im Hirn )
Jetzt braucht man in diesem Zahlenkreis beim Ausstreichen aber auch nur ab dem Quadrat nur die ausstreichen die auch vorkommen können.
Beispiel 7 ausstreichen: 7x [7,11,13,17,19... man muss also nur noch 8/30 Zahlen ausstreichen, statt vorher 7x[7,8,9,10,11,12,..
Man kann dies aber genauso für alle Zahlen die Teilerfremd zu den ersten 5 Primzahlen 2,3,5,7,11 sind machen.
Und das kann mein Programm, keine Sorge es wird dadurch nicht viel schneller ;-) weil der Aufwand recht schnell sehr groß wird.
Anbei das Negativbeispiel BIS = 6 ( = 17#) dauert doppelt solange wie BIS= 5 = 13# bei 1e9 , welches bei mir das schnellste bei diesem Verfahren ist. Beide belegen etwa 26 Mb.
Einmal 23,?? das andere Mal 11,8 Sekunden für die Zahlen eins bis eine Milliarde (2.3 Ghz,Amd X2)
Gruß Horst
Edit:
A space-efficient fast prime number sieve (1996) als pdf:
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.31.3936&rep=rep1&type=pdf
Meine Version ist scheinbar New_SW
Aber dort
http://citeseerx.ist.psu.edu/search?q=wheel+sieve&submit=Search&sort=rel
findest Du auch richtig schnelle quadratische Siebe , wie das von alzaimar genutzte aus primegen.Siehe auch unten auf
http://www.primzahlen.de/files/referent/kw/sieb.htm
Th69 - Mi 14.01.09 11:35
Es gibt noch einen möglichen Pre-Check:
Quelltext
1: 2: 3: 4:
| if((n * n) % 24 == 1) // wenn man die Schleife bei 5 beginnen läßt (2 und 3 sind ja eh bekannt!) {
} |
Dieser verkürzt die Primzahlsuche nochmals. Man muß nur zusehen, daß (n * n) nicht größer als der maximale Wertebereich der Variablen wird (d.h. am besten int64 benutzen).
Hier mal mein kompletter Code in C++:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26:
| void PrintPrims(ostream &os, unsigned int nMaxPrim) { os << "2, 3";
for(unsigned int n=5; n<=nMaxPrim; n+=2) { unsigned __int64 n2 = n; // avoid overflow if((n2 * n2) % 24 == 1) // pre-check for prim { unsigned int nMax = sqrt(n); bool bPrim = true;
for(unsigned int m=3; m<=nMax; m+=2) if(n % m == 0) { bPrim = false; break; }
if(bPrim) os << ", " << n; } }
os << endl; } |
wobei sqrt(unsignd int) selbst implementiert ist (keine Fließkommazahlenberechnung, sondern mittels Intervallverfahren).
Die Liste der Primzahlen bis 1 Mio. füge ich mal an (ca. 600KB).
Moderiert von
Narses: Anhang gezippt
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!