Grundlagen der Informatik I “Programmierung”

Grundlagen der Informatik I “Programmierung” Grundlagen der Informatik I “Programmierung”

22.08.2013 Aufrufe

1.2.2.3 Diskussion Bei der deskriptiven Problembeschreibung gab es keinen Aufwand für die Programmierung, d.h. Problembeschreibung ist gleichzeitig die Problemlösung. Für funktionale Programme muß man die deskriptive Beschreibung (Regeln 1 bis 3 aus 1.2.1.1) erst in ein Programm umsetzen und diese Umsetzung auch begründen (beweisen) können. Der Aufwand ist also höher. Wozu dann das Ganze, wenn man zusätzlich keine Fragen (ggt(?,n)=t) stellen, sondern nur Funktionen (ggt(m,n)=?) beschreiben kann? Im wesentlichen liegt der Unterschied in der Effizienz. In funktionalen Programmen beschreibt man direkt das Verfahren und überläßt die Lösungssuche nicht einer allgemeinen Suchstrategie. Das Opfer, das zugunsten einer verbesserten Effizienz gebracht werden muß, ist die Programmentwicklung und wesentlicher noch die Rechtfertigung oder Verifikation des Programms. In unserem Fall ist die Rechtfertigung noch einfach: Die Implikationen der Regeln werden in die beiden Fallunterscheidungen überführt. Die Zulässigkeit dieser Transformation kann bewiesen werden. Der Programmieraufwand für funktionale Programme auf der Basis einer deskriptiven Problembeschreibung ist relativ gering, wie Sie im Vergleich zu den nächsten Sprachen sehen werden. Da sie konzeptuell sehr einfach und daher leicht erlernbar sind, werden sie an anderen Universitäten als erste Programmiersprachen in dem Grundstudium eingeführt. Daß sie noch nicht allgemein verwendet werden, liegt ebenso wie bei deskriptiven Sprachen an der Effizienz. In diesen Sprachen steht keine Möglichkeit zur Verfügung einen Wert zu verändern. Bei der Auswertung von Formeln benötigen die neuen Werte auch neue Plätze im Speicher. Das ist besonders kritisch bei komplexen Werten wie Matrizen, bei denen sich nur eine Teilinformation ändert (Wertänderung eines Elements der Matrix). Hier wird stets eine vollständig neue Version des komplexen Wertes aufgebaut, statt nur in der alten Version die Teilinformation zu ändern. Der Effekt ist, daß viel Zeit und Platz benötigt wird beim fortwährenden Umbau von Werten (Matrizen, die sich nur in einem Wert voneinander unterscheiden). Eine Vermeidung dieses Aufwands kann man durch Kenntnis des “Platzes” der Teilinformation erreichen, um dort nur die Teilinformation aber nicht die anderen Teilkomponenten zu ändern. Wir kommen damit zu einem Speicherbegriff, der Plätze bereitstellt, in denen Werte abgespeichert und dort auch abgeändert werden können. Diese Abänderungvorschriften nennt man Anweisungen. Sie bilden die Basis der imperativen Programmiersprachen. Ist die notwendige Kenntnis der Speicherstruktur beschränkt auf das Wissen, daß z.B. nur ganze Zahlen, reelle Zahlen, Texte usw. gespeichert werden können, so spricht man von höheren oder problemorientierten Programmiersprachen (Pascal, Modula, Ada, Fortran, Cobol, Eiffel, disziplinert verwendetes C usw.). Ist jedoch auch das Wissen über die interne Darstellung der Werteklassen als Bitmuster (Codierung der Werte in eine Folge von Nullen und Einsen) notwendig, so spricht man von maschinennahen Sprachen (Familie der Assembler, aber z.T. auch C). Jede dieser Programmiersprachen basiert auf einem ihr eigenen abstrakten “Maschinenmodell”, das erklärt, wie die Programme durchgeführt werden. Für die höheren Programmiersprachen ist dieses Modell konzeptionell einfach, für die maschinennahen Sprachen durch seine Menge von Details unübersichtlich. 1.2.3 Problemorientierte imperative Sprachen Im Gegensatz zu den funktionalen Sprachen, deren Interpretation auf dem bekannten Mechanismus der Funktionsauswertung aufsetzt, müssen wir für die Programmiersprachen zuerst das Grundkonzept einer abstrakten Maschine erklären, damit die Anweisungen an diese Maschine verständlich sind. In ihrer einfachsten Form besteht eine abstrakte Maschine (für Programmiersprachen) aus einer Tabelle, die links die Variablennamen (Namen von Plätzen) und rechts Werte (die momentan gespeicherten Werte der Variablen) hat. Diese Tabelle wird Speicher genannt. Neben dem Speicher gibt es noch den Befehlszähler, der angibt, welcher Befehl im Programm als nächster durchgeführt wird. Die wichtigsten Befehle sind die Vorschrift, den Wert einer Variablen zu ändern (Wertzuweisung) und die Befehle, die angeben, welcher Befehl als nächstes ausgeführt werden soll (Kontrollanweisungen). Bei den letzteren sind die Fallunterscheidung und die Schleife die wichtigsten Befehle.

1.2.3.1 Imperatives Programm Nun entwickeln wir den ggt weiter in Richtung eines Programms in einer imperativen, höheren Programmiersprache (Notation von Pascal). Wenn wir die funktionale Version nochmals anschauen, so sehen wir, daß durch die Rekursion immer wieder die beiden Fallunterscheidungen, jedoch mit veränderten Werten, durchgeführt werden. Geben wir dem ersten Argument den Speicherplatz m, dem zweiten Argument den Speicherplatz n und dem Resultat den Speicherplatz t, so sieht der Speicher vor der Ausführung folgendermaßen aus: Speicher m 12 n 15 t ? noch kein Wert bekannt Die Ausführung der Funktion besteht dann in der Ausführung der Fallunterscheidungen, aber statt des rekursiven Aufrufs mit den veränderten Argumenten werden die entsprechenden Speicherplätze überschrieben: m:=m-n bedeutet, der Wert des Speicherplatzes von m wird mit dem Wert vom m-n überschrieben: if m>n then m:=m-n else if mn 3 then m:=m-n 4 else if mn 3 then m:=m-n 4 else if m

1.2.3.1 Imperatives Programm<br />

Nun entwickeln wir den ggt weiter in Richtung eines Programms in einer imperativen, höheren Programmiersprache<br />

(Notation von Pascal). Wenn wir die funktionale Version nochmals anschauen, so sehen wir, daß durch<br />

die Rekursion immer wie<strong>der</strong> die beiden Fallunterscheidungen, jedoch mit verän<strong>der</strong>ten Werten, durchgeführt<br />

werden. Geben wir dem ersten Argument den Speicherplatz m, dem zweiten Argument den Speicherplatz n<br />

und dem Resultat den Speicherplatz t, so sieht <strong>der</strong> Speicher vor <strong>der</strong> Ausführung folgen<strong>der</strong>maßen aus:<br />

Speicher<br />

m 12<br />

n 15<br />

t ? noch kein Wert bekannt<br />

Die Ausführung <strong>der</strong> Funktion besteht dann in <strong>der</strong> Ausführung <strong>der</strong> Fallunterscheidungen, aber statt des rekursiven<br />

Aufrufs mit den verän<strong>der</strong>ten Argumenten werden die entsprechenden Speicherplätze überschrieben:<br />

m:=m-n bedeutet, <strong>der</strong> Wert des Speicherplatzes von m wird mit dem Wert vom m-n überschrieben:<br />

if m>n<br />

then m:=m-n<br />

else if mn<br />

3 then m:=m-n<br />

4 else if mn<br />

3 then m:=m-n<br />

4 else if m

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!