Autor |
Beitrag |
luckyluc
      
Beiträge: 103
|
Verfasst: Di 13.01.09 16:13
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) 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) 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
|
|
Nersgatt
      
Beiträge: 1581
Erhaltene Danke: 279
Delphi 10 Seattle Prof.
|
Verfasst: Di 13.01.09 16:47
Schau mal hier:
de.wikipedia.org/wiki/Primzahltest
Du hast bisher die Probedivision umgesetzt.
_________________ Gruß, Jens
Zuerst ignorieren sie dich, dann lachen sie über dich, dann bekämpfen sie dich und dann gewinnst du. (Mahatma Gandhi)
|
|
Jelly
Hält's aus hier
Beiträge: 3
|
Verfasst: 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
      
Beiträge: 918
Erhaltene Danke: 158
Win 10
VS 2013, VS2015
|
Verfasst: 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
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 
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Di 13.01.09 18:21
Hallo,
Gab es hier alles schon, sind aber viele Beiträge :
www.delphi-forum.de/...t=contest+primzahlen
Gruß Horst
|
|
platzwart
      
Beiträge: 1054
Erhaltene Danke: 78
Win 7, Ubuntu 9.10
Delphi 2007 Pro, C++, Qt
|
Verfasst: Di 13.01.09 20:32
Primzahlen (>3) sind immer in der Form von 6n+/-1
_________________ Wissenschaft schafft Wissenschaft, denn Wissenschaft ist Wissenschaft, die mit Wissen und Schaffen Wissen schafft. (myself)
|
|
Boldar
      
Beiträge: 1555
Erhaltene Danke: 70
Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
|
Verfasst: Di 13.01.09 21:44
Wirklich? Ist das bewiesen?
|
|
Hidden
      
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: 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,
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
|
|
JayEff
      
Beiträge: 2971
Windows Vista Ultimate
D7 Enterprise
|
Verfasst: Mi 14.01.09 00:23
_________________ >+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: 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:
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
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Mi 14.01.09 02:17
Hallo,
heute habe mal eine Uraltversoin von Anfang 2001 ausgegraben:
wheel-sieving (Bei 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:
citeseerx.ist.psu.ed...ep=rep1&type=pdf
Meine Version ist scheinbar New_SW
Aber dort citeseerx.ist.psu.ed...=Search&sort=rel
findest Du auch richtig schnelle quadratische Siebe , wie das von alzaimar genutzte aus primegen.Siehe auch unten auf www.primzahlen.de/fi...referent/kw/sieb.htm
Einloggen, um Attachments anzusehen!
Zuletzt bearbeitet von Horst_H am Mi 14.01.09 15:04, insgesamt 1-mal bearbeitet
|
|
Th69
      

Beiträge: 4798
Erhaltene Danke: 1059
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: 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
Einloggen, um Attachments anzusehen!
|
|
|