athena.gif (7242 Byte)

Übungen zu Nichtabweisenden Schleifen
- Repeat ... Until ... -
    

1. Übertragung Struktogarmm in Quelltext
2. "Schreibtischtest" von zyklischen Strukturen
    2.1. Beispielaufgabe und Lösung
    2.2. Aufgabe zum Schreibtischtest
3. Programmieraufgabe "Eigenwilliger Kredit"
    - Synchronisation von TListBox-Komponenten
    - Ausgabe im Währungsformat

  

    1. Übertragung Struktogramm in Quelltext:

Als algorithmische Kontrollstrukturen kennen wir von den vorangegangenen Seiten Sequenzen, Alternativen und nichtabweisende Zyklen. Diese lassen sich in Problemlösungsalgorithmen in nahezu beliebiger Weise und Tiefe miteinander kombinieren bzw. ineinander schachteln. Die nachfolgenden Struktogramme sind gemäß Beispiel a) 1:1 in pascalgerechte Notationen zu übersetzen, wobei "a" für eine allgemeine Anweisung und "b" für eine allgemeine Bedingung steht.

  Struktogramm Pascal-Quelltext
a)    zstrukt1.gif (2219 Byte)

 

repeat                
  a1;
  if b1 then
    begin
      a2; a3
    end
  else
    a4
until b2;

b) zstrukt2.gif (2274 Byte)

 

?
c) zstrukt3.gif (2920 Byte)

 

?
d) zstrukt4.gif (2882 Byte)

 

?

    2. "Schreibtischtest" von zyklischen Strukturen:
Zweck: 
  • Erkennen der Variablenbelegungen für verschiedene Eingabewerte,
  • Nachweis, ob eine Abbruchbedingung bei bestimmten Eingabewerten erreicht wird oder nicht.

2.1. Beispielaufgabe und Lösung:

a) Zu testen ist folgender nichtabweisender Zyklus für die Eingabe edit1.text := ‘4’ !

x := StrToInt(edit1.text);
n := 0; y := 1;
REPEAT
  n := n+1;
  y := y*2
UNTIL n = x;
edit2.text := IntToStr(y);

b) Welche mathematische Funktion wird von der Struktur realisiert ?
c) Was würde geschehen, wenn man edit1.text mit ‘-1’ belegt ? - Schlussfolgerung ?

Lösung + Hinweise:

zu a) Der Schreibtischtest erfolgt am besten in Tabellenform. Hier werden alle im Algorithmus relevanten Variablen eingetragen und hinsichtlich der Änderung ihrer Werte beim (gedanklichen) Ablauf des Programmes untersucht. Sind Schleifen im Spiel, so muss nach jedem fiktiven Durchlauf das Erreichen der Abbruchbedingung überprüft werden.
Variablen: x n y
Vorgabe: 4 0 1
Durchläufe: 1. 4 1 2
2. 4 2 4
3. 4 3 8
4. 4 4 16
Abbruch, da n=x
zu b) Hierbei ist die Abhängigkeit der Ausgabevariable(n) von der/den Eingabevariable(n) zu untersuchen, im Beispiel also y = f(x). Erkennt man die Abhängigkeit nicht sofort,  führe man weitere "Schreibtischtests" mit geänderten Eingabevariablen durch!

Im Beispiel beträgt    y = 2x

zu c) Da n bereits im ersten Schleifendurchlauf mit dem Wert 1 belegt ist und in jedem weiteren Durchlauf um 1 erhöht wird, entstünde bei Eingabe von -1 für x eine sog. "Endlosschleife", weil die Abbruchbedingung n=x theoretisch niemals erreicht wird.

In der Praxis endet das Ganze entweder mit einer Fehlermeldung (Bereichsüberschreitung / Stacküberlauf etc.) oder mit einem tobsüchtigen Nutzer, der im schlimmsten Fall irgendwann die Reset-Taste betätigt ;-)

Fazit:

  1. Insbesondere zyklische Strukturen sollten vor dem Programmstart gedanklich daraufhin getestet werden, welche Eingabewerte zu Endlosschleifen o. a. Fehlern führen könnten.
  2. Mit Hilfe einer zu programmierenden Eingabesicherung "zwinge" man den Nutzer dazu, nur "erlaubte" Werte einzugeben.
  3. Da 1. und 2. nie 100% Sicherheit bieten, speichere man jedes in Entwicklung befindliche Programm vor dem Compilieren bzw. Starten.  

2.2. Aufgabe zum Schreibtischtest

a) Das nachstehende Programmstück ist per "Schreibtischtest" für den Eingabewert ‘5’ zu untersuchen !

x := StrToInt(edit1.text);
f := 1;
REPEAT
  f := f * x;
  x := x-1
UNTIL x<1;
edit2.text := IntToStr(f);

b) Welche mathematischen Funktion wird hierbei realisiert ?
c) Welcher Wertebereich darf nicht zur Eingabe verwendet werden und weshalb?

    3. Programmieraufgabe "Eigenwilliger Kredit":
a)  Ein nicht gewinnsüchtiger Vater mit nennenswerten Ersparnissen trifft mit seinem finanzbedürftigen Sohn eine eigenwillige "Kreditvereinbarung":

Der Sohn erhält einen Kredit in gewünschter Höhe. Es werden keine Zinsen erhoben. Nach einem Jahr soll der Sohn die Hälfte der Kreditsumme zurückzahlen. Nach jedem weiteren Jahr beträgt die Rückzahlung jeweils die Hälfte der Rückzahlung des Vorjahres bis nach n Jahren der Kredit getilgt ist.

kredit1.gif (8441 Byte)Man entwerfe einen Algorithmus (Struktogramm) und schreibe ein Programm, welches für beliebige Kreditsummen bei Rundung auf ganze Pfennige die Anzahl der Jahre ermittelt, die bis zur vollständigen Tilgung benötigt werden sowie die jährlich zu zahlende Rate auflistet.

Benötigte Variablen: jahre : ganzzahlig; kredit, rate, tilgung : reelle Zahlen.

Nebenstehende Abbildung zeigt einen Vorschlag zur Oberflächengestaltung, wobei die Ausgabe über drei nebeneinander stehende TListBox-Komponenten erfolgt.

Lösungshinweise: 

  1. Synchronisation von TListBox-Komponenten
  2. Ausgabe im Währungsformat

  

b)  Schon eher etwas für Fortgeschrittene:

Eine günstige Stunde ausnutzend, erreicht der Sohn folgende nicht ganz unwesentliche Modifizierung des Kreditvertrages:

Die Abzahlungen können in umgekehrter Reihenfolge stattfinden, d. h. im ersten Jahr erfolgt die Überweisung der kleinsten Rate. Dies steigert sich bis zum letzten Abzahlungsjahr, in dem die Hälfte der ursprünglichen Kreditsumme fällig wird.

Die Problemlösung von a) ist in Struktogramm- und Programmform entsprechend zu modifizieren!

Lösungshinweise: 

Synchronisation von TListBox-Komponenten

Falls nebeneinander angeordnete TListBox-Komponenten zusammen gehörende Wertereihen enthalten, erwartet der Nutzer eine gewisse Synchronität der Anzeige. Wird im obigen Beispiel etwa in der ListBox1 auf das Jahr Nr. 11 geklickt, so sollen auch in ListBox2 und ListBox3 die zugehörigen Einträge markiert erscheinen.

Die nachfolgende Prozedur passt den jeweiligen ItemIndex (markierten Eintrag) von ListBox2 und ListBox3 an den in ListBox1 markierten Eintrag an.

procedure TForm1.ListBox1Click(Sender: TObject);
  begin
    listbox2.itemindex:=listbox1.itemindex;
    listbox3.itemindex:=listbox1.itemindex;
  end;

Ausgabe im Währungsformat

Der Delphi-Hilfe ist unter dem Stichwort "FloatToStrF" u. a. folgendes zu entnehmen:

Funktion FloatToStrF(Value: Extended; Format: TFloatFormat; Precision, Digits: Integer): String;

Beschreibung

FloatToStrF konvertiert einen durch Value gegebenen Fließpunktwert in seine String-Darstellung.
Der Parameter Format bestimmt das Format des resultierenden Strings.
Der Parameter Precision bestimmt die Genauigkeit des übergebenen Wertes. Er sollte für Werte vom Typ Single auf 7 oder weniger gesetzt sein, für Werte vom Typ Double auf 15 oder weniger und bei Extended-Werten auf höchstens 18.
Die Bedeutung des Parameters Digits hängt vom gewählten Format ab.

ffCurrency    Währungsformat. Der Wert wird in einen String konvertiert, der eine Währungsbetrag angibt. Die Umwandlung wird durch die globalen Variablen CurrencyString, CurrencyFormat, NegCurrFormat, ThousandSeparator und DecimalSeparator gesteuert, die alle mit den Werten initialisiert werden, die in der Windows-Systemsteuerung, Abschnitt Ländereinstellungen angegeben wurden. Die Anzahl Ziffern nach dem Dezimalpunkt wird durch den Parameter Digits bestimmt und muß zwischen 0 und 18 liegen.

Im "Kreditprogramm" könnte das Währungsformat wie folgt in die Ausgabeschleife implementiert werden: Listbox2.Items.Add (FloatToStrF (rate, ffCurrency, 8, 2));