AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

for-Schleife gegen über while-Schleife

Ein Thema von Luckie · begonnen am 21. Mär 2009 · letzter Beitrag vom 23. Mär 2009
Antwort Antwort
Seite 1 von 9  1 23     Letzte »    
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#1

for-Schleife gegen über while-Schleife

  Alt 21. Mär 2009, 02:24
Unser Lehrer hat heute gemeint, dass man es möglichst vermeiden sollte aus Schleifen zu springen. Und wenn es nötig sein sollte, sollte man es im Schleifenkopf machen, also eine while-Schleife nehmen.

Ich habe das jetzt mal ausprobiert:
Delphi-Quellcode:
function IsPLZInArray(SonnenStundenListe: TSonnenStunden; PLZ: Integer): Boolean;
var
  i: Integer;
  CurrentPLZ: Integer;
begin
  i := 0;
  Result := False;

  while (i < length(SonnenStundenListe) - 1) and (not Result) do
  begin
    CurrentPLZ := SonnenStundenListe[i, 0];
    Result := CurrentPLZ = PLZ;
    Inc(i);
  end;
end;
Delphi-Quellcode:
function IsPLZInArray(SonnenStundenListe: TSonnenStunden; PLZ: Integer): Boolean;
var
  i: Integer;
  CurrentPLZ: Integer;
begin
  i := 0;
  Result := False;

  for I := 0 to length(SonnenStundenListe) - 1 do
  begin
    CurrentPLZ := SonnenStundenListe[i, 0];
    if CurrentPLZ = PLZ then
    begin
      Result := True;
      Break;
    end;
  end;
end;
Also ich finde die for-Schleife leichter verständlich. Bei der while-Schleife habe ich fast einen Knoten ins Hirn bekommen, wegen der Abbruchbedingung. Das gilt für mich zumindest wenn es mehr als eine Abbruchbedingung gibt.

Was meint ihr?
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.679 Beiträge
 
Delphi 2007 Enterprise
 
#2

Re: for-Schleife gegen über while-Schleife

  Alt 21. Mär 2009, 02:48
Das wesentliche Problem ist nur die Lesbarkeit. In deinem Beispiel müsste man zunächst den Kopf der zuletzt angeworfenen Schleife suchen um zu wissen was nun wo fortgesetzt wird. Da das Break in einem if-Block, also eine Ebene weiter eingerückt steht, kann man nicht einfach den Block als verlassenes Segment verstehen, sondern man muss u.U. eine ganze Serie von Block-Hierachien beachten.
Bei der while-Version steht gleich am Anfang "Pass mal auf, wenn das und jenes in der Schleife passiert, gehts einfach am Ende genau dieses Blocks weiter.
Das war dann aber auch schon alles, und ich erwische mich selbst auch oft genug dabei Break oder Continue zu verwenden, weil es im Schreibfluss finde ich leichter zu erdenken ist. In manchen Fällen gehe ich dann aber doch nachher noch mal an die Schleifen und baue sie um - einfach nur weil's schöner zu lesen ist, und unsere Programme teilweise auch noch nach 2-3 Jahren mit Änderungswünschen belegt werden, wo es dann doch ganz gut ist schnell zu verstehen was man sich damals so alles dabei gedacht hat =)
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.346 Beiträge
 
Delphi 11 Alexandria
 
#3

Re: for-Schleife gegen über while-Schleife

  Alt 21. Mär 2009, 03:58
Meine ganz klare Meinung: Die for-Variante ist in diesem Fall besser, weil vorher bekannt ist bis wo die Schleife maximal läuft.

Von der Lesbarkeit oder dem Schreiben des Codes ist das für mich persönlich kein großer Unterschied, sofern der Code ordentlich formatiert ist. Mehrfache Abbruchbedingungen benutze ich oft und die zu entwerfen ist auch kein Problem.

Der Grund ist ein anderer. Die for-Schleife kann vom Compiler sehr gut optimiert werden. Und der Zielwert ist bekannt und muss nicht jedesmal überprüft werden. Der Compiler kann ein passendes Register auswählen und die Zählweise optimieren. Das geht bei der While-Schleife nicht. Es muss jedesmal die vorgegebene Bedingung überprüft werden.
Ergebnis mit while:
Delphi-Quellcode:
Unit162.pas.36: i := 0;
004532C9 33F6 xor esi,esi
Unit162.pas.37: Result := False;
004532CB 33DB xor ebx,ebx
004532CD EB0D jmp $004532dc
Unit162.pas.41: CurrentPLZ := SonnenStundenListe[i];
004532CF 8B45FC mov eax,[ebp-$04]
004532D2 8B3CB0 mov edi,[eax+esi*4]
Unit162.pas.42: Result := CurrentPLZ = PLZ;
004532D5 3B7DF8 cmp edi,[ebp-$08]
004532D8 0F94C3 setz bl
Unit162.pas.43: Inc(i);
004532DB 46 inc esi
Unit162.pas.39: while (i < length(SonnenStundenListe) - 1) and (not Result) do
004532DC 8B45FC mov eax,[ebp-$04]
004532DF E84022FBFF call @DynArrayLength // !!! Wird jedesmal aufgerufen
004532E4 48 dec eax
004532E5 3BF0 cmp esi,eax
004532E7 7D04 jnl $004532ed
004532E9 84DB test bl,bl
004532EB 74E2 jz $004532cf
Unit162.pas.45: end;
004532ED 33C0 xor eax,eax
Ergebnis mit for:
Delphi-Quellcode:
Unit162.pas.53: Result := False;
0045333E 33DB xor ebx,ebx
Unit162.pas.55: for I := 0 to length(SonnenStundenListe) - 1 do
00453340 8B45FC mov eax,[ebp-$04]
00453343 E8DC21FBFF call @DynArrayLength // !!! Wird nur einmal aufgerufen
00453348 48 dec eax // überflüssig, siehe unten folgender Quelltext
00453349 85C0 test eax,eax
0045334B 7C15 jl $00453362
0045334D 40 inc eax
0045334E 33D2 xor edx,edx
Unit162.pas.57: CurrentPLZ := SonnenStundenListe[i];
00453350 8B4DFC mov ecx,[ebp-$04]
00453353 8B3C91 mov edi,[ecx+edx*4]
Unit162.pas.58: if CurrentPLZ = PLZ then
00453356 3BF7 cmp esi,edi
00453358 7504 jnz $0045335e
Unit162.pas.60: Result := True;
0045335A B301 mov bl,$01
Unit162.pas.61: Break;
0045335C EB04 jmp $00453362
Unit162.pas.63: end;
0045335E 42 inc edx
Unit162.pas.55: for I := 0 to length(SonnenStundenListe) - 1 do
0045335F 48 dec eax
00453360 75EE jnz $00453350
Unit162.pas.64: end;
00453362 33C0 xor eax,eax
Aus dem Grund ist die for-Schleife deutlich besser geeignet unter der Voraussetzung, dass man wie in diesem Fall vorher weiß wie lange die Schleife laufen soll (von der Abbruchbedingung abgesehen). In der Schleife muss dann hier in diesem Fall nur noch eine selbst geschriebene Bedingung ausgeführt werden.

Am optimalsten sieht das Ergebnis aus, wenn man direkt High benutzt, dann spart man auch noch das -1:
Delphi-Quellcode:
function IsPLZInArrayFor2(SonnenStundenListe: TSonnenStunden; PLZ: Integer): Boolean;
var
  i: Integer;
  CurrentPLZ: Integer;
begin
  Result := False;

  for I := 0 to High(SonnenStundenListe) do
  begin
    CurrentPLZ := SonnenStundenListe[i];
    if CurrentPLZ = PLZ then
    begin
      Result := True;
      Break;
    end;
  end;
end;
Delphi-Quellcode:
Unit162.pas.70: Result := False;
0045333E 33DB xor ebx,ebx
Unit162.pas.72: for I := 0 to High(SonnenStundenListe) do
00453340 8B45FC mov eax,[ebp-$04]
00453343 E8E421FBFF call @DynArrayHigh
00453348 85C0 test eax,eax
0045334A 7C15 jl $00453361
0045334C 40 inc eax
0045334D 33D2 xor edx,edx
Unit162.pas.74: CurrentPLZ := SonnenStundenListe[i];
0045334F 8B4DFC mov ecx,[ebp-$04]
00453352 8B3C91 mov edi,[ecx+edx*4]
Unit162.pas.75: if CurrentPLZ = PLZ then
00453355 3BF7 cmp esi,edi
00453357 7504 jnz $0045335d
Unit162.pas.77: Result := True;
00453359 B301 mov bl,$01
Unit162.pas.78: Break;
0045335B EB04 jmp $00453361
Unit162.pas.80: end;
0045335D 42 inc edx
Unit162.pas.72: for I := 0 to High(SonnenStundenListe) do
0045335E 48 dec eax
0045335F 75EE jnz $0045334f
Unit162.pas.81: end;
00453361 33C0 xor eax,eax
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
Satty67

Registriert seit: 24. Feb 2007
Ort: Baden
1.566 Beiträge
 
Delphi 2007 Professional
 
#4

Re: for-Schleife gegen über while-Schleife

  Alt 21. Mär 2009, 05:49
Aus irgendeinem verstaubten Lehrbuch sitzt bei mir auch noch im Kopf: Kein Goto, Kein Break, Kein Exit

Also auch quasi die Aussage, wenn eine For-Schleife ein Break braucht, verwende While.

Ich halte mich schon lange nicht mehr daran, weil es richtig verwendet, nicht die Lesbarkeit zerstört. Man soll ja sowieso Schleifeninhalte möglichst klein halten, dann ist der Zusammenhang nicht weit auseinander gerissen. Mit etwas Erfahrung ist es selbst mir bei beiden Versionen leicht gefallen, den Sinn der Schleifen zu verstehen. Auch Exit am Funktions-Anfang, um sich eine weitere If-Ebene zu sparen, halten ich persönlich für Ok.

Die Beispiele von jaenicke fand ich jetzt auch sehr lehr- und aufschlussreich. Denn ohne mir Gedanken zu machen, hatte ich noch immer die Meinung, das While der For-Schleife in Sachen Geschwindigkeit überlegen ist. Das das falsch ist, sieht man so sehr schön. Auch der Vorteil von High() hätte ich nicht erwartet.

Btw: Macht die vorherige Zuweisung auf die lokale Variable CurrentPLZ überhaupt Sinn?

PS: Goto gehört natürlich trotzdem in kein Pascal-Code, war auch bei mir noch nie nötig.
  Mit Zitat antworten Zitat
Benutzerbild von Matze
Matze
(Co-Admin)

Registriert seit: 7. Jul 2003
Ort: Schwabenländle
14.929 Beiträge
 
Turbo Delphi für Win32
 
#5

Re: for-Schleife gegen über while-Schleife

  Alt 21. Mär 2009, 06:28
Unser Informatik-Professor rät auch ganz klar zur For-Schleife, wenn diese verwendet werden kann. Als Vorteile nannte er hauptsächlich, dass keine Endlosschleifen entstehen können und die Lesbarkeit oft einfacher ist. Trotz break oder continue.

Grüße, Matze

PS: Ein sehr kurzer Beitrag, aber man sieht mal die gegensätzlichen Meinungen von Dozenten.
PPS: Sebastians Beitrag ist wirklich interessant. Dass "High" (minimal) schneller ist als die "-1"-Variante, wusste ich nicht.
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#6

Re: for-Schleife gegen über while-Schleife

  Alt 21. Mär 2009, 06:41
Zitat von Satty67:
Btw: Macht die vorherige Zuweisung auf die lokale Variable CurrentPLZ überhaupt Sinn?
Kann ich nicht sagen. Es erhöht aber die Lesbarkeit und man kann es einfacher debuggen.

So, erst hatte ich meine for-Schleifen zu while-Schleifen gemacht und nach jaenickes Beitrag wieder zurück gebaut, weil er mich doch bestätigt hat. Da wären zum einem die technischen Gründe und dann noch die gefühlten Gründe, wie sie Satty67 erwähnt hat.

Aber einen hätte ich noch:
Delphi-Quellcode:
function GetNextLowerPLZFromList(var PLZ: Integer; PLZSunHours: TPLZSunHours): Integer;
begin
  // Raises EPLZNotInList exception if no lower PLZ can be found
  Result := PLZ;

  while (not IsPLZInList(PLZ, PLZSunHours)) and (PLZ <> -1) do
  begin
    Dec(PLZ);
    Result := PLZ;
  end;
  if PLZ = -1 then
    Raise EPLZNotInList.Create(rsENotInList);
end;
Mit
Delphi-Quellcode:
Type
  TPLZSunHours = array[0..4, 0..1] of Integer;

const
  PLZSunHours: TPLZSunHours = ((34126, 1200), (34127, 2100), (54123, 1000), (80459, 5210), (90785, 1500));
Ich denke, hier muss man eine while-Schleife nehmen. Aber die Abbruchbedingungen verursachen mir noch Kopfschmerzen. Das sieht irgendwie komisch bzw. umständlich aus.

Zur Aufgabe: Gegeben ist eine zwei dimensionale Liste mit PLZ Zahlen und Sonnenstunden pro Jahr. Nach Eingabe der Postleitzahl sollen die zugehörigen Sonnenstunden ausgegeben werden. Ist die PLZ nicht in der Liste, soll die nächst niedrigere genommen werden. Wird keine PLZ gefunden soll -1 ausgegeben werden. Aus der -1 habe ich eine Exception gemacht, aber das ist nebensächlich. (Das ist ein Aufgabe aus der Abschlussprüfung für Fachinformatiker. Dort sollte das allerdings nur in Pseudocode gelöst werden.)

Beim Schreiben des Codes habe ich mich versucht an die Regeln für sauberen Code zu halten, wie es in Clean Code dargestellt wird.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.346 Beiträge
 
Delphi 11 Alexandria
 
#7

Re: for-Schleife gegen über while-Schleife

  Alt 21. Mär 2009, 07:16
Zitat von Luckie:
Zitat von Satty67:
Btw: Macht die vorherige Zuweisung auf die lokale Variable CurrentPLZ überhaupt Sinn?
Kann ich nicht sagen. Es erhöht aber die Lesbarkeit und man kann es einfacher debuggen.
Naja, es ist ein Assemblerbefehl mehr.
Code:
mov edi,[ecx+edx*4]
cmp esi,edi
Ohne die Zuweisung kann der Wert bei ecx+edx*4 auch direkt mit dem Wert im esi Register verglichen werden. Da aber meistens mehr mit der Variablen gemacht wird als ein simpler Vergleich, habe ich es so gelassen.

Denn meistens wird mehrfach auf den Eintrag im Array zugegriffen in der Schleife, was dann viel mehr Aufwand ist. Deshalb ist es meistens mit Zwischenvariable schon besser, also wollte ich das nicht ausgerechnet ansprechen, auch wenn es hier einen Assemblerbefehl mehr kostet.

Zitat von Luckie:
Das sieht irgendwie komisch bzw. umständlich aus.
Ja, aber nicht unbedingt wegen der Bedingung. Du weist am Anfang doch ohnehin PLZ an Result zu. Wofür benutzt du danach denn trotzdem weiter PLZ und legst jedesmal wieder den neuen Wert in Result?
Delphi-Quellcode:
function GetNextLowerPLZFromList(var PLZ: Integer; PLZSunHours: TPLZSunHours): Integer;
begin
  // Raises EPLZNotInList exception if no lower PLZ can be found
  Result := PLZ;

  while (not IsPLZInList(Result, PLZSunHours)) and (Result <> -1) do
    Dec(Result);
  if Result = -1 then
    Raise EPLZNotInList.Create(rsENotInList);
end;
Sinnvoller wäre aber ja wohl eine Betrachtung des nächstkleineren Arrayeintrags statt alle Postleitzahlen durchzuprobieren.
Dafür müsstest du nur einmal dein Array durchgehen und alle vorhandenen Postleitzahlen betrachten. Das geht selbst bei einem unsortierten Array vermutlich schneller. Schließlich werden in deinem Array ja nicht so viele Postleitzahlen sein.
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
Benutzerbild von TheMiller
TheMiller

Registriert seit: 19. Mai 2003
Ort: Gründau
2.480 Beiträge
 
Delphi XE7 Architect
 
#8

Re: for-Schleife gegen über while-Schleife

  Alt 21. Mär 2009, 09:46
Zitat von Luckie:
Unser Lehrer hat heute gemeint, [...]
Morgen,

darf ich fragen, was du machst? Machst du eine Fortbildung oder sowas in der Art? Bei deinem Wissen, Deine Tuts und deine Non-VCL-Programme fällt mir es schwer zu glauben, dass du hier

a) von einem Lehrer im klassischen Sinne redest und
b) Dich ernsthaft mit den "Grundlagen" von Pascal beschäftigst.

Versteh mich nicht falsch, wenn dich deine Frage - zurecht - interessiert ist das ok. Mir ging es nur darum, dass du sagtest, dass dein Lehrer das meinte.

Wenn du magst, dann erzähl mir (oder uns) doch, was du momentan machst, und wofür du einen Lehrer hast, der dir Delphi erklärt

Freundliche Grüße
  Mit Zitat antworten Zitat
Benutzerbild von Matze
Matze
(Co-Admin)

Registriert seit: 7. Jul 2003
Ort: Schwabenländle
14.929 Beiträge
 
Turbo Delphi für Win32
 
#9

Re: for-Schleife gegen über while-Schleife

  Alt 21. Mär 2009, 09:59
Schau hier:

Zitat:
Fachinformatiker / Anwendungsentwickler (2. Le(e/h)rjahr)
Stand: 09/2007

Dann wird es aktuell vermutlich das 3. und letzte Lehrjahr sein.
  Mit Zitat antworten Zitat
Benutzerbild von Meflin
Meflin

Registriert seit: 21. Aug 2003
4.856 Beiträge
 
#10

Re: for-Schleife gegen über while-Schleife

  Alt 21. Mär 2009, 12:44
Luckie, erlich gesagt habe ich keine Ahnung, was du für ein Problem mit derartigen Abbruchbedingungen in while-Schleifen hast

Das ist ein absolutes Standardkonstrukt...
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 9  1 23     Letzte »    


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:06 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz