Etwas über „subroutines“ - Humboldt

Werbung
Etwas über „subroutines“1
Einführung
Wir sind innerhalb der letzten beiden Spielzeug-Experimente relativ schnell zu mehr oder
weniger langen Programm-Codes gelangt. Ziel dieses Kapitels soll sein, in die Thematik der
übersichtlichen Programmierung einzuführen. Dies geschieht anhand von „subroutines“
(Unter-Programmen bzw. Funktionen). Sub-Routinen können als verallgemeinerte
Methoden angesehen werden, die sich nicht nur auf einen speziellen Objekttyp
beschränken, sondern Allgemeingültigkeit besitzen.
Bisher haben wir wann immer es ging, Analoga bestimmter Programmieraspekte in der
realen Welt eingeführt, um uns mit den abstrakten Konzepten vertraut zu machen. Wie
sieht nun das Analoga zur Sub-Routine aus? Stellen Sie sich vor, Sie haben eine Aufgabe
immer und immer wieder zu machen, z.B. die Berechnung eines Mittelwertes einer
Datenserie. Sie haben vermutlich, als Sie das erste mal einen Mittelwert oder eine
Standardabweichung berechnet haben, dies noch von Hand mit dem Taschenrechner
gemacht. Ab einer gewissen Anzahl von Wiederholungen, ist das Konzept, wie man den
Mittelwert oder die Standardabweichung berechnet bekannt. Die Berechnungen weiter per
Hand zu machen erscheint wenig sinnvoll, da dies nur sehr zeitaufwendig ist, und kein
weiterer Lerneffekt zu erwarten ist. An dieser Stelle benutzen Sie wahrscheinlich irgendein
Statistik-Programm (vielleicht auch ein Tabellenkalkulationsprogramm), bei dem Sie die
Daten einfach eingeben, und auf ein Knopfdruck sehr schnell und sicher der Mittelwert
oder die Standardabweichung berechnet wird.
Wir wollen dies nun auch innerhalb von Presentation machen. Bereits im zweiten
Experiment haben wir eine realistische Reaktionszeitmessung via „Stimulus-Manager“
durchgeführt. Wir wollen nun zwei Arten von Sub-Routinen unabhängig voneinander
einführen. Die erste Art der Sub-Routinen sind jene Unterprogramme, die ausgeführt
werden, ohne einen Rückgabe-Wert zu erzeugen. Die ist vergleichbar mit dem Austragen
von normaler Post, da die Routine in diesem Fall einfach lautet: stecke die richtige Post in
den richtigen Briefkasten. Es gibt jedoch auch Briefe, die per Einschreiben verschickt
werden. Bei diesen Briefen muss der Postmann den Brief an den jeweiligen Adressaten
persönlich aushändigen. Die Sachgemäße Briefzustellung wird dann mit einer Unterschrift
des Adressaten bestätigt. Die Unterschrift kann als Rückgabe-Wert angesehen werden.
Eine Sub-Routine wird in Presentation in der folgenden Form geschrieben:
sub
[ return_value ] name [ argument_list ]
begin
subroutine_body
end
Wobei „name“ den Namen der jeweiligen Sub-Routine meint. Lassen Sie uns das Konzept
der Sub-Routinen anhand der Mittelwert-Routine mit bzw. ohne Rückgabe-Wert (returnvalue) genauer anschauen.
Der arithmetische Mittelwert wird bekanntlich dadurch bestimmt, dass über alle Werte
summiert wird, und anschließend das Ergebnis durch die Anzahl der Werte dividiert wird.
1 Stand: 14.11.2010, Sven Blankenburg, Humboldt-Universität zu Berlin
1
Subroutines ohne Rückgabe-Wert
Die folgende Sub-Routine bestimmt den arithmetischen Mittelwert eines eindimensionalen
Arrays.
1 sub
2
average (array< int,1 >& a)
3 begin
4
double mean = 0.0;
5
loop
6
int i = 1;
7
until
8
i >a.count();
9
begin
10
mean = mean + double(a[i]);
11
i = i + 1;
12
end;
13
mean = mean/double(a.count());
14
term.print("Mittelwert: "+string(mean)+"\n");
15 end
In der zweiten Zeile sehen wir, dass der Name unserer Sub-Routine „average“ lauten soll.
Als Argumenten-Liste („argument-list“) wird der Sub-Routine ein eindimensionales Array
(vom Typ integer, d.h. dass alle Elemente im Array vom Typ integer sein müssen)
übergeben, dass innerhalb der Sub-Routine als „a“ bezeichnet werden soll. In der 4. Zeile
definieren wir uns eine sogenannte „double-Zahl“, d.h. Eine Gleitkommazahl mit dem
Namen „mean“ (Mittelwert). Es ist schnell ersichtlich, dass wir mit der bisher eingeführter
integer-Zahl (ganze Zahl) bei der Mittelwert-Bildung nicht auskommen, da der Mittelwert
einer beliebigen Zahlenreihe vom Typ Gleitkommazahl ist. Wir setzen dann auch gleich den
Wert des Mittelwertes auf „0.0“. Würden wir nur den Wert auf „0“ setzen, so würde
Presentation vor der Ausführung eine Fehlermeldung ausgeben, dass wir versuchen eine
ganze Zahl (hier: 0) einer Gleitkommazahl zuzuordnen (hier mean). In der darauf folgenden
fünften Zeile führen wir die Summation aller Elemente der Zahlenreihe mithilfe einer
Schleifen-Konstruktion („loop-until-Konstruktion“) aus. Als Abbruchbedingung für die
Summation setzen wir in der 8. Zeile die Länge des Eingangs-Arrays (hier a) an. Dies
geschieht mit der Methode: count(). Diese gibt die Anzahl der Elemente im Array als ganze
Zahl wieder (dies ist eine spezielle Variante der subroutines mit Rückgabe-Wert). Wenn die
Summierung aller Array-Elemente fertig ist, so muss das Ergebnis noch durch die Anzahl
der Array-Elemente dividiert werden. Dies wird in der 13. Zeile gemacht.
2
Unser Beispiel-Programm könnte nun wie folgt aussehen:
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
# begin of SDL - header ******************************************
scenario = "statistics 1";
default_font_size = 18;
response_matching = simple_matching;
# end of header SDL **********************************************
# begin of SDL ***************************************************
# end of SDL *****************************************************
# begin of PCL ***************************************************
begin_pcl;
sub
average (array< int,1 >& a)
begin
double mean = 0.0;
loop
int i = 1;
until
i >a.count();
begin
mean = mean + double(a[i]);
i = i + 1;
end;
mean = mean/double(a.count());
term.print("Mittelwert: "+string(mean)+"\n");
end
array <int> daten[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
array <int> daten2[10] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
average(daten);
average(daten2);
# end of PCL *****************************************************
In der 14. Zeile sehen wir die Definition der Sub-Routine, so wie wir es weiter oben bereits
besprochen haben.
Man sieht auch, dass Sub-Routinen eine Funktion des PCL-Teils sind, und keine Gültigkeit
im SDL-Teil haben.
In der 30. Zeile legen wir ein Array an, dass 10 Elemente enthält, die alle vom Typ Integer
(int) sind.
Wir wollen nun den Mittelwert dieser Daten berechnen. Dies wird in der 32. Zeile
durchgeführt, wobei das Daten Array einfach unserer Mittelwert-Sub-Routine als
Parameter übergeben wird.
3
Nun soll noch auf einige Spezialfälle hingewiesen werden.
•
In Sub-Routinen definierte Objekte besitzen außerhalb der Sub-Routine keine
Gültigkeit.
• Objekte, die außerhalb der Sub-Routine definiert sind, sind innerhalb der SubRoutine nicht ansprechbar (keine Gültigkeit).
• Objekte, die innerhalb einer Schleifen-Konstruktion definiert werden, besitzen
außerhalb der Schleifen-Konstruktion keine Gültigkeit.
Subroutines mit Rückgabe-Wert
Wir wollen uns nun der Sub-Routinen mit Rückgabe-Werten beschäftigen. Uns schwebt
dabei vor, dass wir uns eine Sub-Routine „basteln“, die bei gegebenen Eingangswerte
einfach wie eine Art „Block-Box“ den arithmetischen Mittelwert in Form eines RückgabeWertes zurück gibt (ähnlich der Methode: cout(), die wir benützt haben, um die Länge eines
Arrays zu ermitteln). Die Modifikationen, die wir an unserer bisherigen Sub-Routine
vornehmen müssen, sind nun wirklich kaum der Rede wert (keine Panik, ein paar Worte
werden wir schon noch darüber verlieren). Was müssen wir ändern?
Erstens müssen wir den Typ eines Rückgabe-Wertes angeben. Dies könnten wir in unserem
Falle wie folgt machen:
1
2
3
4
sub
double average (array< int,1 >& a)
begin
...
In der zweiten Zeile sagen wir einfach nur, dass der Rückgabe-Wert der Sub-Routine eine
Gleitkommazahl (double) ist. Nun müssen wir nur noch sagen, welcher Wert zurück
gegeben werden soll. In unserem Falle ist es natürlich der Mittelwert, also die
Gleitkommazahl mit dem Namen „mean“.
26
mean = mean/double(a.count()); return mean;
27 end
Das beenden der Sub-Routine mit gleichzeitiger Rückgabe eines Werte erfolgt mit dem
Befehl: return.
Wann immer in einer Sub-Routine der Befehl return erfolgt, wird die SubRoutine augenblicklich beendet.
4
Das waren auch schon alle Veränderungen, die wir vornehmen mussten, um unsere SubRoutine nun schon in einer Art „Deluxe“-Variante zu benützen.
Das komplette Programm sieht nun wie folgt aus:
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
29
30
31
32
33
34
35
36
37
38
39
# begin of SDL - header ******************************************
scenario = "statistics 1";
default_font_size = 18;
response_matching = simple_matching;
# end of header SDL **********************************************
# begin of SDL ***************************************************
# end of SDL *****************************************************
# begin of PCL ***************************************************
begin_pcl;
sub
double average (array< int,1 >& a)
begin
double mean = 0.0;
loop
int i = 1;
until
i >a.count();
begin
mean = mean + double(a[i]);
i = i + 1;
end;
mean = mean/double(a.count()); return mean;
end
array <int> daten[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
array <int> daten2[10] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
double mean_value1 = average(daten);
double mean_value2 = average(daten2);
term.print("1. Mittelwert: "+string(average(daten))+"\n");
term.print("2. Mittelwert: "+string(average(daten2))+"\n");
# end of PCL *****************************************************
5
Etwas über das Auslagern von Programmteilen
Bisher haben wir immer wieder auf bereits entwickelte Methoden und Programmteile
älterer Programme zurück gegriffen, und diese via copy-and-pass in unser zu entwerfendes
Programm eingefügt. Wir können uns beispielsweise vorstellen, dass wir die Routine zur
Mittelwert-Berechnung immer einmal wieder verwenden wollen. Wir müssten dann in
jedem PCL-Teil die Sub-Routine von Hand einfügen. Dies scheint wenig sinnvoll zu sein, da
dadurch unser Programm-Code relativ schnell unübersichtlich wird. Wir wollen daher
bestimmte Routinen oder Objekte so auslagern, dass wir sie ohne viel Mühe in beliebigen
Programmen benützen können. Dies realisieren wir mit dem Befehl: include.
Wir wollen die Sub-Routinen vor unserem Auge verstecken, da uns im allgemeinen gar
nicht interessiert, bzw. wir wissen es ja längst, was die Sub-Routine macht. Wir erstellen uns
eine neue Datei, die wir „statistics.pcl“ nennen wollen. In dieser Datei kopieren wir die
gesamte Definition unserer Mittelwert-Bildungs-Routine (natürlich gleich die
„Deluxe“-Variante) hinein. Wir speichern die Datei und sorgen dafür, dass sie sich im
gleichem Ordner befindet, wie die Scenario-Datei, innerhalb derer wir die Sub-Routine
benützen wollen. Unser Scenario könnte nun wie folgt aussehen:
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
# begin of SDL - header ******************************************
scenario = "statistics 1";
default_font_size = 18;
response_matching = simple_matching;
# end of header SDL **********************************************
# begin of SDL ***************************************************
# end of SDL *****************************************************
# begin of PCL ***************************************************
begin_pcl;
include "statistics.pcl";
array <int> daten[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
array <int> daten2[10] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
double mean_value1 = average(daten);
double mean_value2 = average(daten2);
term.print("1. Mittelwert: "+string(average(daten))+"\n");
term.print("2. Mittelwert: "+string(average(daten2))+"\n");
# end of PCL *****************************************************
Wir müssen nur einmal pro Programm dafür sorgen, dass Presentation weiß, woher er die
Sub-Routine „average“ bekommen kann. Dies geschieht mit dem Befehl: include
"statistics.pcl"; in der 15. Zeile.
Der Rest des Scenarios ist wie gehabt.
Mit dem Befehl: include kann man nicht nur vordefinierte Sub-Routinen in
das Programm einbinden, sondern auch vordefinierte Objekte, z.B. arrays.
6
Zugehörige Unterlagen
Herunterladen