Autor |
Beitrag |
enyaw_ecurb
      
Beiträge: 16
|
Verfasst: Mi 12.10.05 15:22
Ich habe neulich eine ganz simple Mandelbrotfunktion geschrieben und wollte die dann optimieren bzw. testen. Da ich die Punkte in einem zweidimensionalen Array gespeichert hab und ich ja nur die Laufzeit der Rechnungen messen wollte hab ich die entsprechende Zeile entfernt. Als Folge darauf ist mein Code aber um ca. eine Sekunde langsamer geworden! Dabei verbraucht der Zugriff doch eigentlich Rechenzeit und die Funktion sollte schneller werden?
Für die Optimierung ist das ja eigentlich irrelevant, aber es hat mich einfach so gewundert das ich das jetzt hier poste.
Der Code:
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:
| procedure Mandelbrot; var counterv, counterh, counteri: integer; Pointv, Pointh: Double; Stepv, Steph: Double; Sizev, Sizeh: integer; Zreal, Zimag, tmp: Double; Density: integer; Bild: array[0..767,0..1023] of Double; begin Sizev := 768; Sizeh := 1024; Steph := 3 / Sizeh; Stepv := 2 / Sizev; Pointv := 1; Density := 2000; counterv := 0;
while counterv < Sizev do begin counterh := 0; Pointh := -2; while counterh < Sizeh do begin Zreal := 0; Zimag := 0; counteri := 0; while (counteri < Density) and (sqr(Zreal) + sqr(Zimag) < 4) do begin tmp := sqr(Zreal) - sqr(Zimag) + Pointh; Zimag := Zreal*Zimag*2 + Pointv; Zreal := tmp; counteri := counteri+1; end; Bild[counterv, counterh] := counteri / Density; Pointh := Pointh + Steph; counterh := counterh+1; end; Pointv := Pointv - Stepv; Counterv := counterv+1; end; end; |
Die Zeitmessung wurde mit QueryPerformanceCounter durchgeführt und unter Delphi 5 kompiliert. Falls euch der Code oder die Variablenbezeichnungen stören...
Es geht bei meiner Frage nur um den Grund der Verlangsamung. Ich weiß selber, dass das da oben nicht so toll ist.
Also testet es am Besten mal und ich hoffe, dass einer von euch den Grund weiß und ich bedanke mich im Voraus für die Antworten.
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mi 12.10.05 21:04
Lach nich, bei mir verdoppelt sich die Zeit, wenn ich die Zeile rausnehme.... WENN ICH DIE ZEILE RAUSNEHME!!!
Das ist mir zu hoch 
_________________ Na denn, dann. Bis dann, denn.
|
|
zemy
      
Beiträge: 207
Win XP Prof.
D7
|
Verfasst: Mi 12.10.05 21:45
kann eigentlich nicht sein. Müsste ein Messfehler sein... wiederhohl einfach mal deine Messungen und mach gleich 4.5 und bilde das Mittel. Dürften die Ergebnisse besser werden.
_________________ LifeIsToShortToThinkAboutTheShortness
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mi 12.10.05 21:53
Würde ich auch so sehen, aber die Routine benötigt 30 Sekunden, da sind Messfehler ausgeschlossen.
Probiers doch beim nächsten Mal selbst, bevor Du solche Ratschläge gibst. 
Einloggen, um Attachments anzusehen!
|
|
ManuelGS
      
Beiträge: 173
Win XP HE, Suse Linux
D6, D7, D2005 Personal
|
Verfasst: Mi 12.10.05 22:22
786.432 Arrayfelder + 786.432 FP-Operationen = viel Zeit!
Könnt ihr keine Mathe mehr? 
_________________ "Leben ist gänzlich Bühne und Spiel; so lerne denn spielen
und entsage dem Ernst - oder erdulde das Leid." - Palladas von Alexandria
|
|
Grishnak
      
Beiträge: 221
Windows XP Home
Delphi 7 PE, Delphi 2005 PE
|
Verfasst: Mi 12.10.05 22:25
Tja, würde gerne helfen, aber bei mir läuft diese Prozedur (fast) nicht!
Als VCL-Anwendung oder Consolen-Anwendung (D7) bekomme ich bei Zeile 10 ('begin') eine StackOverflow-Exception (bzw. die Consolen-Anwendung steigt einfach aus). Wenn ich Zeile 27 auskommentiere, läuft die Prozedur einwandfrei durch! Ich denke, mein Delphi "merkt", dass das Bild-Array nicht benutzt wird und lässt es komplett weg.
Das Problem liegt bestimmt an diesem Bild-Array (immerhin 6 MB groß)!
_________________ Mach' etwas idiotensicher und irgendjemand erfindet einen besseren Idioten!
|
|
ManuelGS
      
Beiträge: 173
Win XP HE, Suse Linux
D6, D7, D2005 Personal
|
Verfasst: Mi 12.10.05 22:34
wenn du die variabel global deklarierst geht es. bei mir braucht das ganze mit oder ohne speichern in "bild" etwa 25,5s.
_________________ "Leben ist gänzlich Bühne und Spiel; so lerne denn spielen
und entsage dem Ernst - oder erdulde das Leid." - Palladas von Alexandria
|
|
Grishnak
      
Beiträge: 221
Windows XP Home
Delphi 7 PE, Delphi 2005 PE
|
Verfasst: Mi 12.10.05 22:38
@enyaw_ecurb & alzaimar: Läuft die Prozedur bei euch auch nur, wenn ihr Bild[] global deklariert? Oder läuft es genau so wie oben geposted? Und wenn ja, warum läuft es bei mir nicht?
_________________ Mach' etwas idiotensicher und irgendjemand erfindet einen besseren Idioten!
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mi 12.10.05 22:46
Ich musste die Bild-Variable global deklarieren.
MIT Zuweisung zum Array werden 15 Sekunden benötigt, OHNE Zuweisung 28 Sekunden.
_________________ Na denn, dann. Bis dann, denn.
|
|
Grishnak
      
Beiträge: 221
Windows XP Home
Delphi 7 PE, Delphi 2005 PE
|
Verfasst: Mi 12.10.05 23:04
Ich habe "Bild: array[0..767,0..1023] of Double;" durch "Bild: array of array of Double" ersetzt, es am Anfang der Prozedur per "SetLength(Bild, 768, 1024)" die Größe angepasst und es am Schluss der Prozedur mit "SetLength(Bild, 0)" gelöscht. Ergebnis: Mit und ohne Zuweisung (Zeile 27) braucht es nun bei mir 17-18 Sekunden!
_________________ Mach' etwas idiotensicher und irgendjemand erfindet einen besseren Idioten!
|
|
enyaw_ecurb 
      
Beiträge: 16
|
Verfasst: Mi 12.10.05 23:09
Tja, da ist mir wohl ein Fehler unterlaufen, sorry. Ich hatte die Arraydeklaration wegen der Übersichtlichkeit in die Prozedur gepackt und es natürlich ausprobiert. Leider war die Zeile von den letzten Tests noch auskommentiert...
Also ich bin auf jeden Fall vollends verwirrt denn ich hab noch ein paar Durchläufe
gemacht. Dazu hab ich die Variable Density, die innerste Iteration, auf verschiedene
Werte gestellt, die Funktion 50 mal durchlaufen lassen und den Durchschnittswert errechnet.
Density: Ohne Zeile, Mit Zeile
1: 45ms, 52ms
10: 238ms, 321ms
100: 1491ms, 1294ms
Insofern völlig normal und entgegen dem Verhalten, das ich beschrieben hab.
Wenn ich aber dann Density auf 1000 oder höher stelle - ja, ich habs keine 50 mal durchlaufen lassen, sondern nur 10 - bekomme ich falsche Durchschnittswerte, die Funktion brauch viel länger als normal, usw. Wenn ichs aber nur zwei- oder dreimal mache ist sie mit der Zeile wieder schneller. ARRGHHH
Ich hab heute auf jeden Fall nicht mehr die Nerven das nochmal zu prüfen, aber ich denke das Ganze wird schon irgendwie an einem Messfehler liegen oder zumindest damit zu tun haben.
Gute Nacht und danke für die Antworten.
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Do 13.10.05 13:33
Hallo,
bei meinem Duron 800 tut sich da fast nichts, ob mit oder ohne diese Zeile.
Es bleiben ja nur 768*1024 Zugriffe, aber 400.576.414 Berechnungen.
Vielleicht sind modernere CPU's da ein bisschen zickiger.
Gruss Horst
P.S.
Ich habe auch Konstanten verwendet, statt Variablen, falls das einen Unterschied macht.
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: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59:
| const Sizev = 768; Sizeh = 1024;
var Bild: array[0..SizeV-1,0..SizeH-1] of Double; {$R *.dfm} function Mandelbrot:int64; var counterv, counterh, counteri: integer; Pointv, Pointh: Double; Stepv, Steph: Double; Zreal, Zimag, tmp: Double; Density: integer;
begin result :=0; Steph := 3 / Sizeh; Stepv := 2 / Sizev; Pointv := 1; Density := 2000; counterv := 0;
while counterv < Sizev do begin counterh := 0; Pointh := -2; while counterh < Sizeh do begin Zreal := 0; Zimag := 0; counteri := 0; while (counteri < Density) and(sqr(Zreal) + sqr(Zimag) < 4) do begin tmp := sqr(Zreal) - sqr(Zimag) + Pointh; Zimag := Zreal*Zimag*2 + Pointv; Zreal := tmp; inc(Counteri); inc(result) end; Bild[counterv, counterh] := counteri / Density; Pointh := Pointh + Steph; counterh := counterh+1; end; Pointv := Pointv - Stepv; Counterv := counterv+1; end; end;
procedure TForm1.Button1Click(Sender: TObject); var t1,t0,f,Erg : int64; begin queryperformancefrequency(f); queryperformancecounter(t0); Erg :=Mandelbrot; queryperformancecounter(t1); Button1.Caption := Format('Zeit %10.5f %20d',[(t1-t0)/f,Erg]); end; |
|
|
|