Steuerstrukturen
Fallunterscheidung(Abfragen) und Wiederholungen(Schleifen)
Eine Besonderheit: Der Zeitgeber (Timer)
Fallunterscheidung (Abfragen)
Die Fallunterscheidung ist einer grundlegensten
Konzepte imperativer Programmiersprachen.
Neben den auch aus anderen
Programmiersprachen bekannten If-THEN-ELSE gibt es noch die eine
ELSEIF Klausel.
In eckigen Klammer Angeführtes ist optional, d.h. kann weggelasssen
werden.
Die mehrzeilige Fallunterscheidung hat folgende
Syntax :
IF Boolescher Ausdruck THEN
Anweisungsfolge...
[ELSEIF Boolescher Ausdruck THEN
Anweisungsfolge...
[ELSEIF Boolscher Ausdruck THEN
Anweisungsfolge...]
....]
[ELSE
Anweisungsfolge....]
END IF
Es gibt noch eine einzeilige IF-Anweisung. Die Syntax dazu lautet: IF
Boolescher Ausdruck THEN Anweisungen [ELSE Anweisungen]
In der mehrzeiligen Variante kann es beliebig viele ELSEIF Blöcke
geben. Der ELSE Block entfallen kann.
Die Auswertung der booleschen
Terme erfolgt dabei in der angegebenen Reihenfolge.
D.h. ist ein Ausdruck wahr,
so wird sein Zweig ausgeführt und die nachfolgenden Terme
werden nicht
mehr ausgewertet, also auch nicht mehr ausgeführt.
So ist es beispielsweise
möglich, in nicht ausgewerteten Bedingungen (möglicherweise) undefinierte
Ausdrücke anzugeben.
Beispiel:
IF x = 3 THEN
...
ELSEIF x = 4 THEN
...
ELSEIF x = 5 THEN
...
ELSE
...
END IF
Beispiel: Nicht strikte Auswertungen
Das folgende Beispiel macht
keinerlei Probleme, obwohl eine Division durch eine Variable durchgeführt wird,
die
ja möglicherweise Null ist. Ist dies nämlich der Fall, so wird der
ELSEIF-Audruck gar nicht ausgewertet. IF
x = 0 THEN
...
ELSEIF 1/x > 0 THEN
...
END IF
Für einfache Fallunterscheidungen bietet sich auch die einzeilige
IF-Anweisung an:
Beispiel: Einzeilige IF-Anweisung
Soll der
Kehrwert eine Zahl x berechnet werden (also 1/x), man kann aber nicht
garantieren,
dass x ungleich Null ist, so muss man dies vor der Division
abfangen.
Im folgenden Beispiel wird für x = 0 das Ergebnis Null in die Variable
result geschrieben,
ansonsten der Kehrwert von x.
IF NOT (x = 0) THEN result = 1/x ELSE result = 0
Die SELECT CASE-Anweisung
Die SELECT CASE Anweisung
bietet die Möglichkeit einen festen Ausdruck auf
verschiedene Werte zu testen
und dem entsprechend zu reagieren.
Syntax:
SELECT CASE testausdruck
CASE ausdruck-1
[Anweisungen-1]...
[CASE ausdruck-n
[Anweisungen-n]]
[CASE ELSE
[Anweisungen des Else-Zweiges]]
END SELECT
Testausdruck ist der Ausdruck, der auf die verschiedenen Werte geprüft
werden soll.
Es können beliebig viele CASE Blöcke und optional ein
CASE ELSE Zweig folgen.
Die Ausdrücke ausdruck-1 bis ausdruck-n
können dabei durch Komma getrennte Listen,
Bereich in der Form a TO b
oder Vergleiche in der Form IS Vergleichsoperator ausdruck
sein.
Beispiel: Signum-Funktion
Das folgende Beispiel liefert
je nach Vorzeichen der Variable x die Werte result=-1 bei negativem x,
result=0
bei x = 0 und result=+1 bei positivem x. Das gleiche leistet die Anweisung
result = SGN(x). SELECT CASE x
CASE is < 0
result = -1
CASE x = 0
result = 0
CASE ELSE
result = 1
END SELECT
Beispiel: Einfacher Primzahl-Test
Wie leistungsfähig die SELECT
CASE Anweisung ist, demonstriert das folgende Beispiel,
das für natürliche
Zahlen x, die kleiner 30 sind, feststellt, ob sie Primzahlen sind. DIM
result AS String
SELECT CASE x
CASE 2,3,5,7,11,13,17,19,23,29
result = "x ist Primzahl"
CASE 0 TO 1
result = "x zwischen Null und Eins"
CASE is < 0
result = "x ist negativ"
CASE is > 30
result = "x ist größer als 30"
CASE
END SELECT
Die SELECT CASE Anweisung kann natürlich auch als
IF-THEN-ELSE Anweisung implementiert werden,
wie gleich an diesem
Beispiel vorgeführt wird. Diese Lösung ist allerdings äußerst unelegant,
was
natürlich für SELECT CASE spricht. DIM
result AS String
IF x=2 OR x=3 OR x=5 OR x=7 OR x=11 OR x=11 OR x=13 _
OR x=17 OR x=19 OR x=23 OR x=29 THEN
result = "x ist Primzahl"
ELSEIF 0 =< x AND x =< 1 THEN
result = "x zwischen Null und Eins"
ELSEIF x < 0 THEN
result = "x ist negativ"
ELSEIF x > 30 THEN
result = "x ist größer als 30"
ENDIF
SCHLEIFEN
FOR - SchleifeDie FOR-Schleife (gezählte Schleife) hat folgende
Syntax :
FOR Variable = Startwert TO Endwert [STEP Schrittweite]
Anweisungsfolge
...
[EXIT FOR]
...
NEXT [Variable]
Bei der gezählten Schleife wird eine Zählvariable von einem Startwert zu
einem Endwert hochgezählt (heruntergezählt).
Das Vorzeichen der Schrittweite
gibt an, ob hoch- oder heruntergezählt wird.
Vor jedem Schleifendurchlauf wird
überprüft, ob der Zähler schon echt größer (echt kleiner) als der Endwert ist.
In diesem Fall wird die Schleife nicht mehr ausgeführt.
Das EXIT FOR
verlässt die Schleife ohne Auswertung des Zählers und kann entfallen.
Es ist
zu beachten, dass der Zähler und auch Start- und Endwert, falls diese als
Variablen vorliegen,
innerhalb der Schleife nicht geändert werden sollten (das
ist das kein besonders guter Stil,
da das Programm dadurch nicht lesbarer
wird!).
Ferner sollte der Zähler nach Bendigung der Schleife auch nicht weiter
verwendet werden
(in manchen Programmiersprachen ist der Zähler nach einer
FOR-Schleife die obere Grenze der Schleife oder auch obere Grenze plus Eins).
Manche Compiler-Hersteller treffen zwar Aussagen über diese Grenzfälle, aber
ob die auf anderen Plattformen oder anderen Programmiersprachen gelten, ist mehr
als fraglich. Damit wird eine Portierung erheblich erschwert.
Beispiel: FOR-Schleife
Das folgende (nicht sonderlich
sinnvolle) Beispiel summiert die ersten tausend Zahlen auf. DIM
summe AS INTEGER
DIM i as INTEGER
FOR i = 1 TO 1000
summe = summe + i
NEXT i
Beispiel: Rückwärts gezählte Schleife
Die folgende Schleife
macht genau dasselbe nur in umgekehrter Reihenfolge.
DIM summe AS INTEGER
DIM i as INTEGER
FOR i = 1000 TO 1 STEP -1
summe = summe + i
NEXT i
WHILE - SchleifeDie WHILE-Schleife ist eine Schleife mit
Anfangsbedingung. Vor jedem Schleifendurchlauf wird die Bedingnung ausgewertet
und bei dem Ergebnis FALSE wird die Schleife verlassen.
Die
WHILE-Schleife hat folgende Syntax :
WHILE Boolescher Ausdruck
Anweisungsfolge....
WEND
Beispiel: Wurzel von a
Das folgende Beispiel berechnet die
Quadratwurzel von a = 2 mit einer Genauigkeit von epsilon = 0.001. Das Ergebnis
wird in der Variablen result abgelegt. Um einzusehen, dass result wirklich gegen
Wurzel a geht, muss man sich erstmal vor Augen führen, dass das Ganze gegen eine
Zahl z konvergiert (was nicht so einfach ist). Für ein solches z muss gelten: z
= 0.5*(z+a/z). Multipliziert man diese Gleichung mit z, so ergibt sich:
z2 = 0.5*z + 0.5*a. Und daraus ergibt sich z2 = a. (Einen
ausführlichen Beweis findet man beispielsweise im Buch Analysis I von Otto
Forster, Vieweg Verlag.) DIM epsilon AS
DOUBLE
DIM result AS DOUBLE
DIM a AS DOUBLE
a = 2
result = a / 2
epsilon = 0.001
WHILE ABS(result^2 - a) >= epsilon
result = 0.5*(result+a/result)
WEND
DO LOOP - Schleife
Die DO LOOP-Schleife ist die
flexibelste Schleife. Mit ihr kann man sowohl unbedingte Schleifen,
als auch
Schleifen mit Anfangs-, End- und Abbruchbedingung realisieren.
Die unbedingte
Schleife (Syntax 1) wird durch die Abbruchanweisung EXIT DO im
Schleifenrumpf verlassen.
Die Schleife mit Anfangsbedingung (Syntax 2)
entspricht der WHILE Schleife.
Bei der Schleife mit Endbedingung
(Syntax 3) wird nach jedem Schleifendurchlauf überprüft,
ob der Ausdruck noch
wahr ist, im Gegensatz zur Schleife mit Abbruchbedingung (Syntax 4),
in der nach
jedem Schleifendurchlauf geprüft wird, ob die Abbruchbedingung schon erfüllt
ist.
Die Syntax lautet:
| Syntax 1 - unbedingte Schleife
| Syntax 2 - Schleife mit Anfangsbedingung
|
DO
Anweisungsfolge
....
EXIT DO
....
Anweisungsfolge
....
LOOP
| DO
WHILE Boolescher Ausdruck
Anweisungsfolge
....
[EXIT DO]
....
LOOP
|
|
|
| Syntax 3 - Schleife mit Endbedingung
| Syntax 4 - Schleife mit Abbruchbedingung |
DO
Anweisungsfolge
....
[EXIT DO]
....
LOOP WHILE
Boolescher Ausdruck
| DO
Anweisungsfolge
....
[EXIT DO]
....
LOOP UNTIL
Boolescher Ausdruck
|
Bei den letzten beiden Schleifentypen wird
der Rumpf mindestens einmal ausgeführt. Schleifen der ersten Art haben
sinnvollerweise mindestens ein EXIT DO und werden unmittelbar bei der
Ausführung dieses Befehls verlassen. Die EXIT DO's können in der
zweiten, dritten und vierten Syntax-Form entfallen.
Beispiel 1:
Arithmetisches Mittel
Beispiel (1) berechnet das arithmetische Mittel
(engl. mean) von echt positiven Zahlen in einem Array, die letzte Zahl ist dabei
von einer Null gefolgt. DIM x (1 TO 10)
AS BYTE
DIM mean AS SINGLE, sum AS INTEGER
DIM i AS INTEGER
x(1) = 1
x(2) = 4
x(3) = 3
x(4) = 0
i = 0
DO
i = i + 1
IF x(i) = 0 THEN EXIT DO
sum = sum + x(i)
LOOP
durchschnitt = sum / (i-1)
Beispiel 2: Quotient und Rest
Beispiel (2) führt eine
Ganzzahldivision mit Rest durch. Dabei enthählt quotient = x \ y und remainder =
x MOD y.
(Dies ist zugegebenermaßen nicht sehr effizient.)
DIM x AS INTEGER, y AS INTEGER
DIM quotient AS INTEGER
DIM remainder AS INTEGER
x = 77
y = 13
quotient = 0
DO WHILE x >= y
x = x - y
quotient = quotient + 1
LOOP
remainder = x
Beispiel 3: Wurzel von a mit Endbedinung
Beispiel (3) berechnet
die Wurzel einer Zahl a mit Hilfe einer Schleife mit Endbedingung. Dabei legt
epsilon die Genauigkeit fest.
DIM epsilon AS DOUBLE
DIM result AS DOUBLE
DIM a AS DOUBLE
a = 2
result = a / 2
epsilon = 0.001
DO
result = 0.5*(result+a/result)
LOOP WHILE ABS(result^2 - a) >= epsilon
Beispiel 4: Wurzel von a mit Abbruchbedinung
Beispiel (4)
berechnet ebenso die Wurzel einer Zahl a, diesmal aber mit Hilfe einer Schleife
mit Abbruchbedingung.
DIM epsilon AS
DOUBLE
DIM result AS DOUBLE
DIM a AS DOUBLE
a = 2
result = a / 2
epsilon = 0.001
DO
result = 0.5*(result+a/result)
LOOP UNTIL ABS(result^2 - a) < epsilon
Das
Zeitgeber-Objekt (Timer, Uhr)
Das Zeitgeberobjekt löst ein Ereignis in
regelmäßigen Intervallen (Zeiteingabe in Millisekunden) aus.
Dadurch kann ebenfalls eine zeitgesteuerte Wiederholung realisiert werden.