FORTRAN - Institut für Wirtschaftsinformatik der WWU Münster ...
FORTRAN - Institut für Wirtschaftsinformatik der WWU Münster ...
FORTRAN - Institut für Wirtschaftsinformatik der WWU Münster ...
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
Westfälische Wilhelms-Universität <strong>Münster</strong><br />
Ausarbeitung<br />
<strong>FORTRAN</strong><br />
im Rahmen des Seminars „Programmiersprachen“<br />
Themensteller: Prof. Dr. Herbert Kuchen<br />
Betreuer: Prof. Dr. Herbert Kuchen<br />
<strong>Institut</strong> <strong>für</strong> <strong>Wirtschaftsinformatik</strong><br />
Praktische Informatik in <strong>der</strong> Wirtschaft<br />
im Fachbereich Informatik<br />
am Lehrstuhl <strong>für</strong> Praktische Informatik<br />
Robert Moeck
Inhaltsverzeichnis<br />
1 Einführung ................................................................................................................. 1<br />
2 Historische Entwicklung............................................................................................ 2<br />
3 Ausgewählte Features von Fortran ............................................................................ 4<br />
3.1 Grundlegende Struktur eines Fortran-Programms............................................ 4<br />
3.2 Typkonzept ....................................................................................................... 6<br />
3.3 Selbstdefinierte Ausdrücke............................................................................... 7<br />
3.4 Zeiger................................................................................................................ 7<br />
3.5 Fel<strong>der</strong> ................................................................................................................ 8<br />
Speicherverwaltung und dynamische Kontrolle ........................................................ 9<br />
3.6 Zuordnungen................................................................................................... 10<br />
3.6.1 Zuordnung über Namen.............................................................................. 10<br />
3.6.2 Zuordnung über Zeiger ............................................................................... 11<br />
3.6.3 Zuordnung über den Speicher..................................................................... 11<br />
3.7 Ein- und Ausgabe............................................................................................ 12<br />
Formatierung........................................................................................................... 13<br />
4 Anwendungsgebiete von Fortran-Systemen ............................................................ 15<br />
Parallele Programmierung...................................................................................... 15<br />
5 Quick Sort................................................................................................................ 17<br />
6 Zusammenfassung und Ausblick............................................................................. 19<br />
A Fortran 95-Quellcode <strong>für</strong> Quick Sort (rekursiv)...................................................... 20<br />
Literaturverzeichnis ........................................................................................................ 22<br />
II
1 Einführung<br />
Die vorliegende Arbeit stellt die problemorientierte Programmiersprache Fortran vor.<br />
Als erste Hochsprache blickt Fortran auf eine Geschichte von rund 50 Jahren zurück<br />
und ist während dieser Zeit vielfach überarbeitet worden. Die Pioniere von Fortran<br />
haben zwar nicht die Idee erfunden, Programme in einer Hochsprache zu schreiben und<br />
den Quellcode zu kompilieren, aber sie haben die erste erfolgreiche Hochsprache<br />
entwickelt. Einen kurzen Überblick über die historische Entwicklung von Fortran gibt<br />
Kapitel 2.<br />
Darauf folgend werden in Kapitel 3 ausgewählte Eigenschaften und Spezifikationen <strong>der</strong><br />
Sprache näher beleuchtet. Dabei wird weniger auf allgemeine Eigenschaften, wie z.B.<br />
Datentypen o<strong>der</strong> Konstrukte, über die nahezu alle Programmiersprachen verfügen,<br />
eingegangen. Vielmehr werden die Beson<strong>der</strong>heiten <strong>der</strong> Sprache Fortran hervorgehoben<br />
und erläutert.<br />
Im 4. Abschnitt werden die typischen Anwendungsgebiete von Fortran-Programmen<br />
dargestellt und Ansätze zur parallelen Programmierung beleuchtet.<br />
Anschließend wird die im Rahmen dieses Seminars programmierte Beispielanwendung<br />
Quick Sort vor- und <strong>der</strong> Implementierung in Java gegenübergestellt.<br />
Die Ausarbeitung wird mit einer kurzen Zusammenfassung und einem Ausblick in<br />
Kapitel 6 abgeschlossen.
Kapitel 2: Historische Entwicklung<br />
2 Historische Entwicklung<br />
<strong>FORTRAN</strong> I – Mitte <strong>der</strong> 1950er-Jahre verfügten die Rechner über äußerst kleine<br />
Hauptspeicher in <strong>der</strong> Größenordnung von 15 KB, waren langsam und hatten, wenn<br />
überhaupt, sehr primitive Betriebssysteme. Assembler-Programmierung war gängige<br />
Praxis. Die geistigen Väter von Fortran (Fortran = FORmula TRANslation), ein IBM-<br />
Team unter <strong>der</strong> Leitung von John W. Backus, entwickelten 1957 nach dreijähriger<br />
Arbeit den <strong>FORTRAN</strong>-I-Compiler. Beson<strong>der</strong>s im wissenschaftlichen und militärischen<br />
Bereich verbreitete sich die neue Sprache schnell – die Vorteile lagen auf <strong>der</strong> Hand:<br />
Anwendungen, die zuvor Wochen <strong>für</strong> ihre Berechnungen brauchten, ließen sich binnen<br />
weniger Stunden abarbeiten. Die Anfor<strong>der</strong>ungen an den Programmierer waren<br />
wesentlich geringer als es bei <strong>der</strong> Assembler-Programmierung <strong>der</strong> Fall war. Und die<br />
Programme wurden portabel!<br />
<strong>FORTRAN</strong> 66 – Die Entwicklung ging (über die Zwischenversionen <strong>FORTRAN</strong> II, III<br />
und IV) weiter, die Sprache erhielt weitere Features. Seit 1962 beschäftigte sich die<br />
ASA (American Standards Association; <strong>der</strong> Vorläufer des ANSI, American National<br />
Standards <strong>Institut</strong>e) mit <strong>der</strong> Entwicklung eines Standards <strong>für</strong> die Fortran, was 1966 mit<br />
<strong>der</strong> gleichnamigen Version als erstem Hochsprachen-Standard abgeschlossen wurde.<br />
<strong>FORTRAN</strong> 77 – Ein weiterer Meilenstein wurde im Jahre 1977 fertig gestellt und 1978<br />
veröffentlicht. Zunächst ein amerikanischer ANSI-Standard, wurde <strong>FORTRAN</strong> 77 kurz<br />
darauf auch von <strong>der</strong> ISO (International Standards Organization) zum Standard erhoben<br />
– dieser galt somit weltweit. In dieser Neuauflage wurden viele wichtige Komponenten,<br />
wie z.B. Block-IF-Strukturen (IF – THEN – ELSE – ENDIF), <strong>der</strong> Pre-Test von DO-<br />
Schleifen (vorher musste man einen Umweg über Sprungmarken nahmen, denn die<br />
Schleife wurde nur ein einziges Mal ausgeführt) und <strong>der</strong> CHARACTER-Datentyp<br />
hinzugefügt.<br />
Fortran 90 und 95 – Dass zwischen <strong>FORTRAN</strong> 77 und seinem Nachfolger über zehn<br />
Jahre lagen, begünstigte, dass an<strong>der</strong>e Programmiersprachen, wie C o<strong>der</strong> C++, sich in<br />
den von Fortran dominierten Anwendungsgebieten – Naturwissenschaften und<br />
Ingenieurwesen – wachsen<strong>der</strong> Beliebtheit erfreuten. Nichtsdestoweniger hat diese späte<br />
Überarbeitung des <strong>FORTRAN</strong> 77-Standards eine Menge mächtiger Erweiterungen<br />
eingeführt. Als wichtigste Neuerungen seien erwähnt: Spaltenunabhängige Codierung<br />
(in allen vorherigen Versionen mussten diesbezüglich strenge Konventionen<br />
2
Kapitel 2: Historische Entwicklung<br />
eingehalten werden), weitere mo<strong>der</strong>ne Kontroll-Strukturen (CASE und DO WHILE),<br />
abgeleitete bzw. abstrakte Datentypen, Operator-Überladung (die Erweiterung bzw. Re-<br />
Definition <strong>der</strong> Funktionalität von Operatoren), dynamische Speicherverwaltung und<br />
Modularisierung. Genauer wird auf die Spezifikationen in Kapitel 3 eingegangen.<br />
Mit Fortran 90 wurde im Prinzip <strong>der</strong> heutige Stand <strong>der</strong> Technik erreicht – die aktuelle<br />
Version, Fortran 95, führte weniger Neues ein, als dass sie die Fehler und<br />
Inkonsistenzen von Fortran 90 korrigierte. Mit den in Fortran 90 implementierten<br />
Features enthielt die Sprache die wichtigsten auch heute noch gebräuchlichen<br />
Konstrukte und wurde wie<strong>der</strong> konkurrenzfähig. Hierbei spielt die Abwärtskompatibilität<br />
eine beson<strong>der</strong>e Rolle: Fortran 90 enthält den vollen Funktionsumfang <strong>der</strong><br />
Vorgängerversion, so dass auch die mo<strong>der</strong>nen Compiler den Code von vor über 20<br />
Jahren verarbeiten können.<br />
3
Kapitel 3: Ausgewählte Features von Fortran<br />
3 Ausgewählte Features von Fortran<br />
Fortran ist eine imperative Programmiersprache. Ein imperatives Programm besteht aus<br />
Anweisungen (Instruktion, Befehl, statement). Es gibt Variablen, <strong>der</strong>en Wert sich durch<br />
Zuweisungen (assignments) än<strong>der</strong>n kann. Imperative Sprachen basieren i. a. auf dem<br />
Von-Neumann-Rechnermodell, d.h. Variablen bezeichnen Speicherplätze, Befehle<br />
richten sich an die CPU. Der Quellcode von Fortran-Programmen muss durch einen<br />
Compiler in semantisch äquivalenten Maschinencode übersetzt werden.<br />
3.1 Grundlegende Struktur eines Fortran-Programms<br />
Ein Hauptprogramm wird durch die Anweisung PROGRAM eingeleitet und durch END<br />
PROGRAM beendet. Dazwischen befinden sich weitere Anweisungen, Funktions- o<strong>der</strong><br />
Subroutinendefinitionen, o<strong>der</strong> Modul-Spezifikationen. Ein einfaches Beispiel:<br />
PROGRAM hallo_welt !Hauptprogramm<br />
CALL hallo !Aufruf einer Subroutine<br />
END PROGRAM hallo_welt !Ende des Hauptprogramms<br />
SUBROUTINE hallo !Definition <strong>der</strong> Subroutine<br />
PRINT *, ‘Hallo Welt!’ !Ausgabe von Hallo Welt!<br />
END SUBROUTINE hallo !Ende <strong>der</strong> Subroutine<br />
Programmeinheiten sind Hauptprogramm, externe Unterprogramme (Funktionen o<strong>der</strong><br />
Subroutinen), block data-Unterprogramme und Module. Mit dem Hauptprogramm<br />
startet die Ausführung eines Programms. Das Hauptprogramm darf (ebenso wie externe<br />
Unterprogramme und Modul-Unterprogramme) hinter <strong>der</strong> Anweisung CONTAINS<br />
interne Unterprogramme enthalten. Durch die geschachtelten Aufrufe von<br />
(Unter-)Programmen entsteht eine hierarchische Struktur von Programmeinheiten. Eine<br />
Baumstruktur ist aber nicht überall streng eingehalten, weil ein Unterprogramm von<br />
vielen Seiten aufgerufen werden kann, und weil es Rekursion gibt.<br />
Funktionen und Subroutinen können extern als eigenständige Programmeinheiten, o<strong>der</strong><br />
intern als Teile an<strong>der</strong>er Programmeinheiten definiert sein. Funktionen werden im<br />
aufrufenden Programm in Ausdrücken benutzt. Subroutinen werden mit CALL<br />
aufgerufen. Die Rekursion wird in Fortran unterstützt. Entsprechende Funktionen o<strong>der</strong><br />
Subroutinen müssen mit dem Schlüsselwort RECURSIVE gekennzeichnet werden. Eine<br />
4
Kapitel 3: Ausgewählte Features von Fortran<br />
Blockdatenprogrammeinheit ist eine nichtausführbare Programmeinheit, mit <strong>der</strong>en Hilfe<br />
Variablen benannter gemeinsamer Speicherbereiche initialisiert werden können.<br />
Ein Modul (seit Fortran 90) ist eine nichtausführbare Programmeinheit, die beliebige<br />
Typvereinbarungen, Spezifikationen, Unterprogramme und/o<strong>der</strong><br />
Schnittstellendefinitionen enthalten darf. Es können sichtbare und private<br />
Modulkomponenten definiert werden, wobei die sichtbaren von an<strong>der</strong>en<br />
Programmeinheiten genutzt werden können [Ge91]. Beispiel:<br />
MODULE testmodul !Modul mit<br />
PUBLIC :: hochdrei !explizit sichtbar<br />
CONTAINS !deklarierter<br />
SUBROUTINE hochdrei(zahl) !Subroutine, die<br />
INTEGER :: ergebnis !ergebnis als Rück-<br />
ergebnis = zahl * zahl * zahl !gabewert hat.<br />
END SUBROUTINE hochdrei<br />
END MODULE testmodul<br />
PROGRAM haupt !Hauptprogramm, das das “Testmodul”<br />
USE testmodul !inkl. öffentlicher Subroutine<br />
CALL hochdrei(5) !”hochdrei” nutzt und<br />
END PROGRAM haupt !5 hoch 3 ausrechnet.<br />
Komplexe Probleme lassen sich mit Hilfe von Unterprogrammen in Teilprobleme<br />
aufspalten. Jedes Teilproblem wird dabei in ein überschaubares Unterprogramm<br />
ausgelagert. Das ist <strong>für</strong> die Menschen, die das Gesamtprogramm entwickeln und<br />
warten, leichter zu überblicken und auf mehrere Mitarbeiter zu verteilen als ein<br />
ungeglie<strong>der</strong>tes Großprogramm. Darüber hinaus können Compiler kleinere Einheiten oft<br />
besser optimieren als große. Sie setzen Register und an<strong>der</strong>e Schnellspeicher geschickter<br />
ein. Allerdings kostet <strong>der</strong> Aufruf von Unterprogrammen auch etwas Zeit, so dass die<br />
Unterprogramme nicht zu wenig beinhalten sollten. Hinsichtlich <strong>der</strong><br />
Wie<strong>der</strong>verwendbarkeit von Programmcode spielt die Modularisierung einer komplexen<br />
Anwendung eine große Rolle: Unterprogramme können in Unterprogramm-<br />
Bibliotheken abgelegt und von mehreren Programmen aus benutzt werden (z.B.<br />
mathematische und statistische Verfahren, Algorithmen zum Suchen und Sortieren,<br />
Graphik- und GUI-Programmpakete). Auch können Debugging-Strategien leichter<br />
genutzt werden, denn die Unterprogramme können einzeln auf Korrektheit untersucht<br />
werden. Natürlich führt die Benutzung von Unterprogrammen zu einer Reduzierung des<br />
gesamten Quellprogramms und auch des entstehenden Maschinenprogrammcodes,<br />
wenn die Unterprogramme mehrfach aufgerufen werden [Gr99].<br />
5
Kapitel 3: Ausgewählte Features von Fortran<br />
3.2 Typkonzept<br />
Fortran benutzt eine statische Typbindung, d.h. <strong>der</strong> Quellcode legt die Datentypen <strong>der</strong><br />
existierenden Größen fest. Damit wird die Typbindung und -prüfung zur<br />
Übersetzungszeit vorgenommen. Fortran ist nicht streng typisiert.<br />
In Fortran müssen nicht alle Variabeln deklariert werden, aber es ist sehr zu empfehlen.<br />
Die grundsätzliche Typkonvention ist: Wird ein Name verwendet, <strong>der</strong> nicht explizit<br />
deklariert ist, nimmt <strong>der</strong> Compiler entsprechend den Anfangsbuchstaben implizit einen<br />
<strong>der</strong> Grundtypen an, und zwar bei i, j, k, l, m, n per Voreinstellung den Typ integer,<br />
sonst real [Gr99].<br />
Mit <strong>der</strong> IMPLICIT-Anweisung können zu diesem Zweck Buchstaben(bereiche)<br />
bestimmt werden, so dass Variablen, die mit entsprechenden Buchstaben beginnen,<br />
automatisch vom festgelegten Datentyp sind. Zwar erspart sich <strong>der</strong> Programmierer<br />
damit die explizite Deklaration, also einige Schreibarbeit, aber damit werden<br />
Schreibfehler in Variablennamen evtl. erst in <strong>der</strong> Testphase erkannt. Beispiel:<br />
IMPLICIT TYPE(student) (s), TYPE(dozent) (d)<br />
!Alle Variablen, die mit S beginnen, sind vom Typ student,<br />
!Alle Variablen, die mit d beginnen, sind vom Typ dozent.<br />
Mit <strong>der</strong> Anweisung IMPLICIT NONE wird die Typkonvention außer Kraft gesetzt, d.h.<br />
<strong>für</strong> jede Variable ist eine explizite Typvereinbarung erfor<strong>der</strong>lich.<br />
Zusätzlich zu den vordefinierten Datentypen können bei Bedarf weitere Typen in<br />
Fortran „abgeleitet“ werden, d.h. mit Hilfe <strong>der</strong> existierenden Typen können neue<br />
Datentypen definiert werden. Ein solcher selbstdefinierter Datentyp hat mindestens eine<br />
Komponente, wobei jede Komponente wie<strong>der</strong>um einen vordefinierten o<strong>der</strong><br />
selbstdefinierten Datentyp spezifiziert. Beispiel:<br />
TYPE wohnort !Datentyp wohnort, <strong>der</strong><br />
CHARACTER (LEN=20) :: strasse !ausschließlich aus<br />
INTEGER :: hausnr !vordefinierten Typen<br />
INTEGER :: plz !besteht.<br />
CHARACTER (LEN=20) :: stadt<br />
END TYPE wohnort<br />
TYPE student !Datentyp student, <strong>der</strong><br />
CHARACTER (LEN=20) :: name !eine Strukturkomponente<br />
INTEGER :: matr_nr !vom Typ wohnort hat<br />
TYPE (wohnort) :: adresse<br />
END TYPE student !bitte wenden…<br />
6
Kapitel 3: Ausgewählte Features von Fortran<br />
TYPE (student), DIMENSION(150) :: ein_student<br />
!Ein Feld mit 150 Studenten<br />
PRINT *, ein_student(42)%matr_nr<br />
!Ausgabe <strong>der</strong> Matr.-Nr. von Student Nr. 42<br />
Speicherfolge. Normalerweise ist durch die Reihenfolge <strong>der</strong> Typkomponenten keine<br />
Speicherfolge gegeben. Wenn die Typdefinition jedoch eine SEQUENCE-Anweisung<br />
enthält, dann spezifiziert die Reihenfolge <strong>der</strong> Typkomponenten eine Speicherfolge <strong>für</strong><br />
Größen dieses Typs. Weiterhin wird durch SEQUENCE bewirkt, dass Größen dieses Typs<br />
mit bestimmten Einschränkungen in COMMON- und EQUIVALENCE-Anweisungen (Kap.<br />
3.7.3) spezifiziert werden dürfen [Ge91].<br />
Sichtbarkeit. Eine Typ- o<strong>der</strong> Komponentendefinition ist privat, wenn sie grundsätzlich<br />
nur innerhalb des Moduls zugänglich ist, das die Typdefinition enthält (PRIVATE-<br />
Attribut). Eine sichtbare Typ- o<strong>der</strong> Komponentendefinition (PUBLIC-Attribut) kann mit<br />
Hilfe von USE auch außerhalb ihres Moduls zugänglich und nutzbar gemacht werden.<br />
3.3 Selbstdefinierte Ausdrücke<br />
Ein selbstdefinierter Ausdruck besteht aus Operanden selbstdefinierten und/o<strong>der</strong><br />
vordefinierten Typs und selbstdefinierten und/o<strong>der</strong> erweiterten vordefinierten<br />
Operatoren [Ge91].<br />
Überladung. Die Funktionalität sowohl vordefinierter, als auch selbstdefinierter<br />
Operatoren kann durch die Definition von mehr als einer Operatorfunktion erweitert<br />
werden. Man spricht von Überladung. Wichtig ist dann die Eindeutigkeit <strong>der</strong><br />
spezifizierten Operatorfunktionen, d.h. je zwei Operatorfunktionen müssen jeweils<br />
mindestens einen Formalparameter gleicher Position haben, die sich hinsichtlich Typ,<br />
Typparameter o<strong>der</strong> Rang unterscheiden. Bei Ausführung eines überladenen Operators<br />
bestimmen die Eigenschaften <strong>der</strong> Operanden, welche Operatorfunktion (implizit)<br />
aufgerufen wird [Ge91].<br />
3.4 Zeiger<br />
„Zeiger“ ist in Fortran kein spezieller Datentyp, son<strong>der</strong>n ein Attribut, das <strong>für</strong> Variablen<br />
o<strong>der</strong> selbstdefinierte Funktionen beliebigen Datentyps spezifiziert werden kann. Eine<br />
Variable o<strong>der</strong> eine Funktion mit POINTER-Attribut ist ein Zeiger. Dieser belegt eine<br />
unspezifische Speichereinheit. Ein Zeiger kann erst dann definiert und benutzt werden,<br />
7
Kapitel 3: Ausgewählte Features von Fortran<br />
wenn er einem Ziel zugeordnet (mittels ALLOCATE) ist – erst dann kann man ihn wie<br />
eine „normale“ Variable behandeln, d.h. je<strong>der</strong> Zugriff auf den Zeiger entspricht einem<br />
Zugriff auf das zugeordnete Ziel. Der Wert eines Zeigers ist also ein Verweis auf eine<br />
an<strong>der</strong>e Datengröße desselben Typs wie <strong>der</strong> Zeiger, d.h. ein Zeiger ist typgebunden.<br />
Es gibt keine Zeigerkonstante, keinen NIL-Zeiger und auch kein Zeigerfeld, dessen<br />
Elemente Zeiger sind. Adressarithmetik ist in Fortran nicht möglich. Das<br />
Dereferenzieren erfolgt automatisch [Ge91].<br />
Jedes Ziel, auf das ein Zeiger weisen soll, muss ein TARGET-Attribut haben, außer bei<br />
dem Ziel handelt es sich selbst um einen Zeiger. Dies dient lediglich <strong>der</strong> Verbesserung<br />
<strong>der</strong> Laufzeit-Effizienz des Fortran-Programms.<br />
Der Zuordnungsstatus eines Zeigers ist entwe<strong>der</strong> „undefiniert“ (z.B. zu Beginn <strong>der</strong><br />
Ausführung eines Programms), „zugeordnet“ o<strong>der</strong> „nicht zugeordnet“. Mittels<br />
ALLOCATE wird ein Zeiger einem (an<strong>der</strong>en) Ziel zugeordnet. Durch NULLIFY o<strong>der</strong><br />
DEALLOCATE wird die Zuordnung aufgehoben. Der Zuordnungsstatus eines Zeigers<br />
darf bei Ausführung eines Unterprogramms geän<strong>der</strong>t werden. Ist die Ausführung des<br />
Unterprogramms beendet, bleibt <strong>der</strong> Zuordnungsstatus bestehen (außer das Ziel wird<br />
beim Rücksprung in das aufrufende Programm undefiniert).<br />
3.5 Fel<strong>der</strong><br />
Ein Feld (array) ist in Fortran eine regelmäßige Anordnung von skalaren<br />
Datenelementen mit gleichem Typ und Typparameter in Zeilen, Spalten, Ebenen,<br />
Kuben (Qua<strong>der</strong>n) usw. (Vektoren, Matrizen, ...). Das einzelne Element ist durch ein<br />
Index-Tupel bestimmt. Ein Feld darf bis zu 7 Dimensionen haben, jede Dimension mit 0<br />
o<strong>der</strong> mehr Elementen.<br />
Aufgrund <strong>der</strong> Feldspezifikation wird neben dem Rang des Feldes (= Anzahl <strong>der</strong><br />
Dimensionen) auch dessen Gestalt bestimmt, wobei die folgenden drei Arten<br />
unterschieden werden:<br />
− Fel<strong>der</strong> mit expliziter Gestalt: Die Index-Grenzen werden <strong>für</strong> jede Dimension<br />
explizit festgelegt, d.h. die Obergrenze muss, die Untergrenze kann <strong>für</strong> jede<br />
Dimension bestimmt werden (falls die Untergrenze fehlt, wird sie gleich 1<br />
gesetzt).<br />
8
Kapitel 3: Ausgewählte Features von Fortran<br />
− Fel<strong>der</strong> mit übernommener Gestalt: Die Gestalt wird vom zugeordneten<br />
Aktualparameterfeld übernommen. Die Größe eines solchen Feldes ist gleich <strong>der</strong><br />
Größe <strong>der</strong> entsprechenden Dimension des zugeordneten Aktualparameterfeldes.<br />
− Fel<strong>der</strong> mit übernommener Größe: Die Größe eines solchen Feldes wird durch<br />
die Größe des zugeordneten Aktualparameterfeldes bestimmt. Im Gegensatz zur<br />
vorgenannten Feldart dürfen sich die zugeordneten Fel<strong>der</strong> hinsichtlich Rang und<br />
Größe <strong>der</strong> Dimensionen unterscheiden.<br />
Speicherverwaltung und dynamische Kontrolle<br />
Ohne Benutzerintervention verläuft die Speicherzuordnung dynamisch. In einigen<br />
Fällen ist es dennoch sinnvoll, Einfluss auf die Speicherverwaltung zunehmen, z.B.<br />
wenn man sicherstellen möchte, dass lokale Variablen eines Unterprogramms nach dem<br />
Rücksprung in das aufrufende Programm ihren Definitionsstatus behalten, o<strong>der</strong> wenn in<br />
einem Unterprogramm ein Feld benötigt wird, dessen Gestalt von einer o<strong>der</strong> mehreren<br />
Variablen abhängen soll, o<strong>der</strong> wenn man nur <strong>für</strong> bestimmte Zeit ein lokales Feld<br />
benötigt, wobei die Gestalt dieses Feldes erst nach einigen Berechnungen dynamisch<br />
festgelegt werden kann. Im ersten Fall kann man COMMON-, DATA- o<strong>der</strong> SAVE-<br />
Anweisungen verwenden, bzw. die entsprechenden Variablen gleich bei Initialisierung<br />
mit dem SAVE-Attribut versehen. Im zweiten Fall ist ein automatisches Feld sinnvoll,<br />
im dritten Fall bieten sich dynamische Fel<strong>der</strong> o<strong>der</strong> Feldzeiger an.<br />
Ein automatisches Feld wird beim Aufruf des Unterprogramms erzeugt. Dabei wird <strong>der</strong><br />
Speicherplatz <strong>für</strong> das jeweilige automatische Feld zugeteilt. Beim Rücksprung in das<br />
aufrufende Unterprogramm wird das Feld wie<strong>der</strong> gelöscht, d.h. <strong>der</strong> Speicherplatz<br />
automatisch wie<strong>der</strong> freigegeben.<br />
Ein dynamisches Feld wird im Spezifikationsteil eines (Unter-)Programms deklariert.<br />
Dabei wird auf Indexgrenzen verzichtet, statt dessen wird dieses dynamische Feld mit<br />
einem ALLOCATABLE-Attribut ausgestattet. Es existiert so lange noch nicht, bis im<br />
Verlauf <strong>der</strong> Ausführung einer Programmeinheit feststeht, welche Gestalt das Feld haben<br />
soll. Dann wird mit Hilfe <strong>der</strong> ALLOCATE-Anweisung die explizite Gestalt des Feldes<br />
spezifiziert und <strong>der</strong> Speicherplatz angefor<strong>der</strong>t, d.h. das Feld wird dynamisch erzeugt. Es<br />
existiert so lange, bis es mit <strong>der</strong> DEALLOCATE-Anweisung wie<strong>der</strong> gelöscht, <strong>der</strong><br />
Speicherplatz also freigegeben wird. Wird ein dynamisches Feld vor dem Rücksprung<br />
9
Kapitel 3: Ausgewählte Features von Fortran<br />
aus seiner Programmeinheit in die aufrufende Programmeinheit nicht gelöscht, ist <strong>der</strong><br />
Existenzstatus „undefiniert“.<br />
Feldzeiger. Wie bei dynamischen Fel<strong>der</strong>n, sind <strong>für</strong> einen Feldzeiger keine Indexgrenzen<br />
spezifiziert. Die Deklaration des Feldzeigers wird aber auch im Spezifikationsteil eines<br />
(Unter-)Programms vorgenommen, wobei die Kennzeichnung als Feldzeiger über das<br />
POINTER-Attribut geschieht. Erst bei Ausführung seines (Unter-)Programms werden<br />
die Indexgrenzen, d.h. die Gestalt des Feldes, festgelegt und <strong>der</strong> entsprechende Speicher<br />
angefor<strong>der</strong>t. Die Erzeugung eines Zielfeldes wird durch eine ALLOCATE-Anweisung<br />
erreicht. Solange diese nicht erfolgt, <strong>der</strong> Zeiger also nicht zugeordnet ist, ist die Gestalt<br />
des Feldzeigers undefiniert.<br />
3.6 Zuordnungen<br />
Die Programmeinheiten sollen natürlich nur in den seltensten Fällen allein <strong>für</strong> sich, d.h.<br />
ohne Kommunikation miteinan<strong>der</strong>, ablaufen. Datenobjekte, Unterprogrammnamen und<br />
an<strong>der</strong>e Objekte werden zwischen den Programmeinheiten weitergereicht. Dabei gibt es<br />
in Fortran folgende Möglichkeiten:<br />
3.6.1 Zuordnung über Namen<br />
Unter Parameterzuordnung versteht man die Weitergabe von Datenobjekten und<br />
externer Unterprogrammnamen mittels aktueller und formaler Parameter. Die in einer<br />
Funktions-Deklaration eingeführten Argumente werden als Formalparameter<br />
bezeichnet. Die vom aufrufenden Programm übergebenen Werte nennt man<br />
Aktualparameter. Zu jedem Aktualparameter muss ein Formalparameter existieren, und<br />
Aktual- und Formalparameter müssen hinsichtlich ihres Typs übereinstimmen. Die<br />
Parameterübergabe erfolgt bei Fortran über Adressen, Aktualparameter und<br />
Formalparameter sind also identisch, ohne Kopie. Bei Konstanten und Ausdrücken wird<br />
eine Hilfsvariable übergeben (nur in Eingaberichtung), wenn eine<br />
Überschreibungsgefahr besteht.<br />
Umgebungszuordnung (host association). Ein Unterprogramm ist in eine größere<br />
Programmeinheit eingebettet und kennt alle (bzw. viele) Daten dieser Umgebung.<br />
Lokale Größen überschreiben dabei allerdings die Größen, die aus <strong>der</strong> Umgebung<br />
übernommen wurden.<br />
10
Kapitel 3: Ausgewählte Features von Fortran<br />
USE-Zuordnung. Gemeinsam genutzte Objekte werden in Modulen angeordnet. Die<br />
Deklarationen im Modul-Spezifikationsteil und die expliziten Schnittstellen zu den<br />
Modul-Unterprogrammen können an<strong>der</strong>en Geltungseinheiten mit Hilfe <strong>der</strong> USE-<br />
Anweisung zur Compilezeit zugänglich gemacht werden (abhängige Compilation).<br />
3.6.2 Zuordnung über Zeiger<br />
Durch Zeigerzuordnung werden ein Zeiger und sein Ziel einan<strong>der</strong> so zugeordnet, dass<br />
das Ziel benutzt o<strong>der</strong> definiert werden kann, indem man dazu auf den Zeiger (und nicht<br />
auf das Ziel) Bezug nimmt. Ein Zeiger kann bei Bedarf einem an<strong>der</strong>en Ziel zugeordnet<br />
werden, und die Zuordnung kann auch je<strong>der</strong>zeit aufgehoben werden. Ein Zeiger ist zu<br />
einem bestimmten Zeitpunkt immer nur höchstens einem Ziel zugeordnet. Umgekehrt<br />
kann ein Ziel je<strong>der</strong>zeit mehreren Zeigern zugeordnet sein (vgl. Kap. 3.4).<br />
3.6.3 Zuordnung über den Speicher<br />
Datenobjekte sind über den Speicher einan<strong>der</strong> zugeordnet, wenn sich ihre<br />
Speicherfolgen mindestens eine gemeinsame Speichereinheit teilen, o<strong>der</strong> wenn ihre<br />
Speichereinheiten unmittelbar aufeinan<strong>der</strong> folgen. Wenn zwei Speicherfolgen eine<br />
bestimmte Speichereinheit gemeinsam belegen, dann sind (soweit die Längen <strong>der</strong><br />
jeweiligen Speicherfolgen das zulassen) auch die jeweils davor liegenden<br />
Speichereinheiten einan<strong>der</strong> zugeordnet. Entsprechendes gilt auch <strong>für</strong> die jeweils<br />
nachfolgenden Speichereinheiten <strong>der</strong> beiden Speicherfolgen.<br />
COMMON-Blöcke. Je<strong>der</strong> gemeinsam genutzte Speicherbereich hat eine Speicherfolge, die<br />
aus den Speicherfolgen aller Variablen besteht, die sich in ihm befinden. COMMON-<br />
Blöcke dienen dem Austausch von Variablen (nicht Formalparameter o<strong>der</strong><br />
Funktionsresultate) zwischen Programmeinheiten. Im Grunde ist ein COMMON-Block ein<br />
Stück Hauptspeicher, das jedes Teilprogramm, falls erfor<strong>der</strong>lich, mitbenutzen darf, die<br />
gemeinsamen Speicherblöcke sind also global. Die Reihenfolge <strong>der</strong> einzelnen<br />
Speicherfolgen ist durch die Reihenfolge <strong>der</strong> entsprechenden Variablen gegeben.<br />
Die COMMON-Anweisung steht in jedem Teilprogramm, das auf den gemeinsamen<br />
Speicherraum zugreift: COMMON [/[CNAME]/] VARIABLE[,VARIABLE]... Es gibt<br />
einen „blanc common“ (ohne CNAME-Attribut) und bei Bedarf viele „named common“<br />
mit eindeutigen Bezeichnern (CNAMEs). Die Variablen im „blanc common“ können im<br />
Gegensatz zu denen im „named common“ nicht initialisiert werden. Die Lebensdauer<br />
11
Kapitel 3: Ausgewählte Features von Fortran<br />
des „blanc common“ ist damit so lang wie die des Hauptprogramms. Dagegen wird <strong>der</strong><br />
Speicherplatz eines nicht mit SAVE gesicherten „named common“ <strong>für</strong> an<strong>der</strong>e Benutzung<br />
freigegeben, wenn keines <strong>der</strong> Teilprogramme mehr aktiv ist, das auf ihn referenziert.<br />
Diese Art <strong>der</strong> Speichernutzung ist allerdings ein „Relikt“ aus den älteren Fortran-Zeiten<br />
und fehleranfällig bzw. wenig überschaubar. Fortran 90-Programme sollten über<br />
Module als die bessere Alternative implementiert werden.<br />
EQUIVALENCE. Über die EQUIVALENCE-Anweisung werden zwei o<strong>der</strong> mehr Größen<br />
einer Programmeinheit einan<strong>der</strong> zugeordnet, indem sie auf dieselbe Speicherfolge<br />
verweisen. So kann dieselbe Information durch verschiedene Namen referenziert<br />
werden. Die EQUIVALENCE-Anweisung führt allerdings keine Typkonversionen durch<br />
und impliziert auch keine Äquivalenz im mathematischen Sinn, son<strong>der</strong>n assoziiert<br />
lediglich Speichereinheiten. Die folgende Abbildung verdeutlicht die Art <strong>der</strong><br />
Zuordnung von bspw. zwei Fel<strong>der</strong>n.<br />
DIMENSION M(3,2),P(6) !zweidimensionales Feld M mit 6<br />
!Elementen, und eindimensionales<br />
!Feld P mit 6 Elementen<br />
EQUIVALENCE (M(2,1),P(1)) !Assoziiert M und P<br />
M(1,1) M(2,1) M(3,1) M(1,2) M(2,2) M(3,2)<br />
P(1) P(2) P(3) P(4) P(5) P(6)<br />
Abb. 3.1: Assoziation zweier Fel<strong>der</strong> mit EQUIVALENCE<br />
Durch das Äquivalent-Setzen wird <strong>der</strong> gemeinsame Speicher bereich u. U. nach hinten<br />
erweitert. Gemeinsame Speicherbereiche dürfen jedoch nie nach vorn erweitert werden.<br />
3.7 Ein- und Ausgabe<br />
Der Grundbaustein des Fortran-Dateisystems ist <strong>der</strong> Datensatz, d.h. eine Folge von<br />
Werten bzw. Zeichen (z.B. eine Zeile auf dem Bildschirm o<strong>der</strong> in einer Datei) mit fester<br />
Länge. Es wird zwischen formatgebundenen (listengesteuerten) und formatfreien<br />
Datensätzen unterschieden, was Einfluss auf die auszuführenden E/A-Anweisungen hat<br />
– formatgebundene Datensätze können nur mit formatgebundenen Anweisungen (d.h.<br />
unter Verwendung des FMT-Attributs) bearbeitet werden, analog verhält es sich bei<br />
12
Kapitel 3: Ausgewählte Features von Fortran<br />
formatfreien Datensätzen. Eine dritte Art von Datensätzen ist <strong>der</strong> Dateiendesatz<br />
(ENDFILE) [Ge91].<br />
Als Datei wird die Folge zusammengehören<strong>der</strong> Datensätze bezeichnet. Sie kann auf<br />
externen Medien abgelegt sein, o<strong>der</strong> intern als Arbeitsspeicherbereich existieren. Es<br />
gibt zwei Zugriffsmethoden: Bei sequenzieller Verarbeitung ist durch die Reihenfolge,<br />
in <strong>der</strong> die Datensätze in die Datei geschrieben werden, auch die Reihenfolge<br />
vorgegeben, in <strong>der</strong> die Datensätze wie<strong>der</strong> gelesen werden können, d.h. <strong>der</strong> n-te<br />
Datensatz kann erst nach dem Lesen <strong>der</strong> (n – 1) vorherigen Datensätze gelesen werden.<br />
Wenn eine externe Datei <strong>für</strong> den direkten Zugriff geöffnet ist, dann können Datensätze<br />
unabhängig von <strong>der</strong> Reihenfolge <strong>der</strong> Datensatznummern geschrieben werden. Die<br />
Datensatznummer wird intern vom Speichermedium verwaltet – die Adresse eines<br />
Datensatzes auf dem Speichermedium kann als Produkt <strong>der</strong> Datensatznummer und <strong>der</strong><br />
(festen) Länge eines Datensatzes berechnet werden. Als Ein- und Ausgabeanweisungen<br />
sehen zur Verfügung:<br />
READ Daten- OPEN BACKSPACE<br />
WRITE CLOSE Dateistatus<br />
übertragung ENDFILE<br />
PRINT<br />
INQUIRE<br />
REWIND<br />
Positionierung<br />
OPEN (11, FILE=’x’, ACCESS=’DIRECT’, FORM=’FORMATTED’, RECL=80)<br />
öffnet bspw. eine Datei „x“ formatgebunden mit direktem Zugriff und einer<br />
Datensatzlänge von 80 Zeichen und verbindet diese mit <strong>der</strong> E/A-Einheit 11. Als weitere<br />
sinnvolle Parameter lassen sich Anweisungsmarken angeben, zu denen gesprungen<br />
wird, wenn z.B. ein Fehler auftritt (ERR=20) o<strong>der</strong> das Dateiende erreicht ist (END=30).<br />
Die Funktion INQUIRE dient <strong>der</strong> Abfrage des Zustands von Dateien und auch Ein- und<br />
Ausgabeeinheiten. Ausschließlich <strong>für</strong> sequenzielle Dateien existieren die drei<br />
Positionierungs-Anweisungen BACKSPACE (= Zurücksetzen <strong>der</strong> Datei um einen<br />
Datensatz), REWIND (= Rücksetzen an den Dateianfang) und ENDFILE (= Ende <strong>der</strong><br />
Datei).<br />
Formatierung<br />
Die Anweisung FORMAT legt in umfangreicher Weise die Formatierung sowohl<br />
eingelesener, als auch auszugeben<strong>der</strong> Daten fest. Alle verfügbaren<br />
Formatspezifikationen an dieser Stelle aufzuzählen, würde den Rahmen dieser Arbeit<br />
sprengen. Abgesehen davon erscheint die Formulierung <strong>der</strong> Format-Attribute auf den<br />
ersten Blick recht kryptisch. Festhalten lässt sich, dass beim Einlesen die Daten in eine<br />
13
Kapitel 3: Ausgewählte Features von Fortran<br />
interne Binärdarstellung konvertiert werden, bei <strong>der</strong> Ausgabe werden sie aus ihrer<br />
internen binären Darstellung entsprechend <strong>der</strong> FORMAT-Anweisung in Zeichenreihen<br />
umgewandelt [Ge91]. Formatgebundene Sätze enthalten die Daten in<br />
Zeichendarstellung, so gut wie immer in menschenlesbarer Form. Allerdings kostet die<br />
Umwandlung von <strong>der</strong> internen Darstellung in die formatierte Darstellung und<br />
umgekehrt ihre Zeit. Bei formatfreier Übertragung wird die interne Darstellung des<br />
benutzten Rechners nicht umgewandelt. Vorteil ist also die Schnelligkeit und<br />
Genauigkeit <strong>der</strong> Abspeicherung. Auch <strong>der</strong> Platzbedarf ist z. T. erheblich geringer: eine<br />
Double-Zahl von 8 Byte interner Darstellung braucht z.B. zur fehlerfreien Wie<strong>der</strong>gabe<br />
ein FORMAT es24.17, also dreimal soviel Platz. Dienen daher die Daten doch wie<strong>der</strong><br />
nur zur Computerverarbeitung, ist die formatfreie Art vorzuziehen. Ein Problem ergibt<br />
sich aufgrund <strong>der</strong> Umwandlung zwischen den internen Zahlendarstellungen vieler<br />
Rechner, wenn formatfreie Dateien zwischen Rechnern mit unterschiedlichen<br />
Zahlendarstellungen ausgetauscht werden sollen [Gr99]. Praktischerweise kann eine<br />
Formatspezifikation auch mit einer Anweisungsmarke versehen werden, so dass sie<br />
immer wie<strong>der</strong> genutzt werden kann.<br />
Eine ausführliche Beschreibung aller Formatspezifikationen geben [Ge91] o<strong>der</strong> auch<br />
[UH84].<br />
14
Kapitel 4: Anwendungsgebiete von Fortran-Systemen<br />
4 Anwendungsgebiete von Fortran-Systemen<br />
Die Programmiersprache Fortran wird bevorzugt zur analytischen und numerischen<br />
Berechnung natur- und ingenieurwissenschaftlicher Probleme benutzt. Wesentlich sind<br />
hohe Ausführungsgeschwindigkeit und gute Lesbarkeit – auch <strong>für</strong> Nicht-Profis. Fortran<br />
ist die älteste höhere Programmiersprache, steht aber zu Unrecht in dem Ruf, veraltet zu<br />
sein. Die Ursachen <strong>für</strong> das Überleben sind recht nahe liegend: ein großer Nutzerkreis<br />
und die Menge an fertigen und laufenden Programmen – <strong>für</strong> nahezu alle<br />
wissenschaftlichen Problemkreise existieren umfangreichste Bibliotheken, die auch<br />
heute noch unentbehrlich sind.<br />
Parallele Programmierung<br />
Hierbei ist das Umdenken von sequenzieller zu paralleler Bearbeitung eines Problems<br />
entscheidend. Es stehen sich SIMD (Single Instruction Multiple Data)- und MIMD<br />
(Multiple Instruction Multiple Data)-Ansätze gegenüber. SIMD bedeutet, dass eine<br />
(einzige) Operation auf mehrere Datenbereiche angewendet wird. Eine Sprache mit<br />
MIMD-Features erlaubt es, simultan unterschiedliche Funktionen o<strong>der</strong> Subroutinen auf<br />
verschiedenen Datenbereichen operieren zu lassen. Die hohe Effizienz von Fortran legt<br />
nahe, dass es sich <strong>für</strong> die Parallelisierung eignet, und es gibt eine Reihe von<br />
Forschungsprojekten, die Fortran z.B. <strong>für</strong> die Simulation komplexer Systeme einsetzen.<br />
Fortran 90 selber hat allerdings wenige bis gar keine MIMD-Konstruktionen [PTVF96].<br />
Fortran 95 als Weiterentwicklung von Fortran 90 bietet durch forall- und PURE-<br />
Konstrukte bessere Möglichkeiten, MIMD-Features zu nutzen [PTVF96]. In einer<br />
an<strong>der</strong>en Weiterentwicklung von Fortran 90, <strong>der</strong> Programmiersprache High Performance<br />
Fortran (HPF) <strong>für</strong> die datenparallele Programmierung sind MIMD-Features gezielt<br />
implementiert. Sie hat eine Reihe industrieller Anwendungen ermöglicht, zu denen u. a.<br />
Deformationsberechnungen von Automobilteilen, Strömungssimulation von<br />
Flugzeugteilen, Staudammberechnungen, die Berechnung elektromagnetischer Fel<strong>der</strong>,<br />
umfangreiche Wetterprognosen und viele weitere gehören [PTVF96].<br />
OpenMP („Open Multi Processing“) ist eine Sammlung von Compiler-Direktiven,<br />
Bibliotheksroutinen und Umgebungsvariablen, die Parallelisierung durch gemeinsame<br />
Speichernutzung in Fortran- und C/C++-Programmen unterstützt. Die Parallelisierung<br />
läuft zum Großteil über parallele Schleifen ab. Dabei wird nach dem Fork-Join-Prinzip<br />
15
Kapitel 4: Anwendungsgebiete von Fortran-Systemen<br />
gearbeitet, d.h. das Problem wird in parallelen Bereichen auf mehrere CPUs verteilt, die<br />
einzelnen Ergebnisse an <strong>der</strong> nächsten seriellen Stelle wie<strong>der</strong> zu einem gemeinsamen<br />
Ergebnis zusammengeführt:<br />
Serieller Bereich<br />
Paralleler Bereich<br />
Serieller Bereich<br />
Paralleler Bereich<br />
Serieller Bereich<br />
0<br />
0<br />
0<br />
0<br />
0<br />
1 2 3<br />
1 2 3<br />
Abb. 4.1: Fork-Join-Prinzip (Quelle: [UH03])<br />
Master Thread<br />
Team of Threads<br />
Master Thread<br />
Team of Threads<br />
Master Thread<br />
16
Kapitel 5: Quick Sort<br />
5 Quick Sort<br />
In Anlehnung an den Pseudo-Code, <strong>der</strong> in [OW96] vorgestellt wird, ist es recht einfach,<br />
den Quick Sort-Algorithmus in Fortran zu implementieren. Als Entwicklungsumgebung<br />
wurde Compaq Visual Fortran 6.6 Professional eingesetzt, eine Anwendung mit großem<br />
Funktionsumfang, um auch größere Fortran-Projekte zu verwalten und zu debuggen. Es<br />
wurde ein Fortran 90-Compiler verwendet. Ausgeführt wurde das fertige Programm auf<br />
einem Intel Celeron II mit 433 MHz und 256 MByte Arbeitsspeicher.<br />
Die Struktur des Proramms glie<strong>der</strong>t sich zunächst in ein Modul qsort_modul und das<br />
Hauptprogramm Quick_Sort. Das qsort_modul enthält wie<strong>der</strong>um zwei öffentliche<br />
und eine private Subroutine: Die private Subroutine partition sorgt <strong>für</strong> das<br />
Weiterbewegen <strong>der</strong> Zeiger, den paarweisen Elementevergleich des zu testenden Arrays<br />
und das Vertauschen <strong>der</strong> Elemente, falls erfor<strong>der</strong>lich. Aufgerufen wird partition von<br />
<strong>der</strong> öffentlichen Subroutine qsort_sub, die rekursiv auf alle Teilbereiche des<br />
übergebenen Arrays angewendet wird, solange <strong>der</strong>en Länge größer Null ist. Die dritte<br />
Subroutine zufall startet einen Zufallsgenerator, <strong>der</strong> das übergebene Array mit<br />
Werten füllt. Eingabeparameter ist die Länge, die im Hauptprogramm bestimmt wird,<br />
Rückgabewert ist das fertig gefüllte Array. Hier<strong>für</strong> wurde eine von Fortran vordefinierte<br />
Subroutine random_number zur Erzeugung einer Pseudozufallszahl verwendet, die in<br />
einer DO-Schleife so oft ausgeführt wurde wie das Array Elemente hat.<br />
Damit ist das Modul qsort_modul zu Ende. Es folgt das Hauptprogramm<br />
Quick_Sort, in dem zunächst die Subroutinen des vorgenannten Moduls mittels USE<br />
qsort_modul eingebunden werden. Anschließend folgt <strong>der</strong> Spezifikationsteil, in dem<br />
alle später verwendeten Variablen deklariert werden. Hier besteht in <strong>der</strong> Variable<br />
laenge die Möglichkeit, die Größe des zu sortierenden Arrays festzulegen. Dieses wird<br />
sogleich durch Aufruf <strong>der</strong> zufall-Subroutine mit entsprechenden Werten gefüllt. Um<br />
die Performance des Sortiervorgangs zu messen, wird die Zeit anhand eines auf <strong>der</strong> Uhr<br />
des Rechners basierenden Funktion gemessen. Diese wird erst initialisiert (auf Null<br />
gesetzt), wobei <strong>der</strong> Parameter count_rate spezifiziert, wie oft pro Sekunde <strong>der</strong> Wert<br />
hochgezählt werden soll (im vorliegenden Fall von count_rate=1000 werden also<br />
Millisekunden gezählt). Anschließend wird <strong>der</strong> Zählvorgang gestartet und <strong>der</strong><br />
Startzeitpunkt in <strong>der</strong> Variablen startzeit gespeichert. Dann folgt <strong>der</strong> Aufruf <strong>der</strong><br />
Subroutine qsort_sub, d.h. das Array wird sortiert. Zuletzt wird wie<strong>der</strong>um die Zeit<br />
17
Kapitel 5: Quick Sort<br />
gemessen und die Differenz gebildet. So kann schließlich die aufgewendete Zeit auf<br />
dem Bildschirm ausgegeben werden. Der vollständige Quellcode kann Anhang A<br />
entnommen werden.<br />
Für den Vergleich mit Java ist die von [Ku03] erstellte Klasse verwendet und um einen<br />
Zufallsgenerator und die Zeitmessung erweitert worden. Der Zufallsgenerator und das<br />
sukzessive Füllen des Testarrays mit Zahlen lässt sich über Random() und eine<br />
Schleife realisieren:<br />
Random r = new Random();<br />
int[] a = new int[5000000];<br />
for (int i = 0; i < a.length-1; i++) a[i] = r.nextInt();<br />
Die Zeitmessung wurde mittels System.currentTimeMillis() bewerkstelligt, was<br />
wie in <strong>der</strong> zuvor besprochenen Fortran-Version vor und nach dem Sortieren ausgeführt<br />
wird, wobei dann die Differenz den Zeitaufwand zeigt. Um den Algorithmus in Java zu<br />
testen, wurde die Entwicklungsumgebung Eclipse 2.1.3 verwendet.<br />
Die Ergebnisse bei<strong>der</strong> Sprachen können <strong>der</strong> folgenden Tabelle entnommen werden:<br />
Array-Größe<br />
Aus<strong>für</strong>ungszeit<br />
[Sek] in Fortran<br />
Ausführungszeit<br />
[Sek] in Java<br />
100 < 0,01 0,010<br />
1.000 0,013 0,020<br />
10.000 0,042 0,020<br />
20.000 0,097 0,081<br />
50.000 0,231 0,150<br />
100.000 0,511 0,271<br />
250.000 1,352 0,762<br />
500.000 2,841 1,732<br />
1.000.000 6,399 3,695<br />
2.000.000 12,478 7,490<br />
5.000.000 33,899 18,266<br />
Tab. 5.1: Dauer <strong>der</strong> Ausführung von Quick Sort<br />
auf einem Intel Celeron II mit 433 MHz und 256 MB Arbeitsspeicher<br />
Es wird deutlich, dass – obwohl auch die in Fortran realisierte Version vergleichsweise<br />
gute Werte erzielt – Java eindeutig effizienter arbeitet. Auch <strong>der</strong> Quellcode ist in Java<br />
um einiges schlanker. Den ca. 70 reinen Lines of Code in Fortran stehen in Java<br />
lediglich ca. 25 Zeilen gegenüber.<br />
18
Kapitel 6: Zusammenfassung und Ausblick<br />
6 Zusammenfassung und Ausblick<br />
„Man könnte Fortran (kurz <strong>für</strong> formula translation), die ursprüngliche „High Level“-<br />
Programmiersprache, <strong>für</strong> das Hightech-Äquivalent zur Keilschrift halten – immerhin ist<br />
es mittlerweile 47 Jahre her, dass IBM sie eingeführt hat. Doch sie wird immer noch<br />
breit eingesetzt, vor allem im wissenschaftlichen Bereich. Warum hat dieser Veteran<br />
aus <strong>der</strong> Eisenhower-Ära so viele Hardware- und Softwaregenerationen überlebt?<br />
„Teilweise ist es die Lernkurve“, sagt Hans Boehm von den Hewlett-Packard<br />
Laboratories, früherer Vorsitzen<strong>der</strong> <strong>der</strong> Programmiersprachen-Gruppe in <strong>der</strong><br />
Association for Computing Research. „Für einige Leute ist sie gut genug, und es ist<br />
schwierig, etwas aufzugeben, was man einmal gelernt hat. Die Anpassbarkeit und<br />
Kompatibilität, die Fortran zur Lingua Franca des Programmierens in den 60er und 70er<br />
Jahren gemacht hat, spielen ebenfalls eine Rolle <strong>für</strong> ihre Langlebigkeit. Größere<br />
Upgrades haben ihre Effizienz verbessert und neue Features gebracht, dabei aber die<br />
älteren Versionen intakt gelassen. Also funktioniert eine riesige Menge von erprobten<br />
Fortran 77-Programmen noch mit dem gegenwärtigen Fortran 90. So macht man das,<br />
Microsoft!“ [Sc04]<br />
Die an<strong>der</strong>en Technologien waren übrigens: Analoguhren, Nadeldrucker,<br />
Schreibmaschinen, Hörfunk, Pager, Tonbän<strong>der</strong>, Vakuumröhren, Faxgeräte und<br />
Mainframe-Computer.<br />
Aufgrund <strong>der</strong> Tatsache, dass in <strong>der</strong> neusten Fortran-Version auch bereits<br />
objektorientierte Konzepte integriert worden sind, und aufgrund <strong>der</strong> bekannten Vorteile,<br />
die die Sprache schon über einen so langen Zeitraum haben erfolgreich sein lassen, wird<br />
sie wohl auch in Zukunft weiterleben und in den bekannten Anwendungsgebieten und<br />
<strong>der</strong> Forschung von großer Bedeutung sein. Ein weiteres Upgrade (Fortran 2000) ist<br />
geplant, die Ankündigungen auf verschiedenen Websites weichen aber bzgl. <strong>der</strong><br />
Veröffentlichung voneinan<strong>der</strong> ab.<br />
19
Anhang A: Titel von Anhang 1<br />
A Fortran 95-Quellcode <strong>für</strong> Quick Sort (rekursiv)<br />
module qsort_modul ! Modul, das vom Hauptprogramm<br />
! genutzt wird.<br />
public :: qsort_sub ! sichtbare Quicksort-Subroutine<br />
public :: zufall ! sichtbarer Zufallsgenerator<br />
private :: partition ! interne Sortier-Subroutine<br />
contains<br />
recursive subroutine qsort_sub(array)<br />
real, intent(in out), dimension(:) :: array<br />
integer :: iq<br />
if(size(array) > 0) then<br />
call partition(array, iq)<br />
call qsort_sub(array(:iq-1))<br />
call qsort_sub(array(iq+1:))<br />
endif<br />
end subroutine qsort_sub<br />
subroutine partition(array, iq)<br />
real, intent(in out), dimension(:) :: array<br />
integer, intent(out) :: iq<br />
integer :: uzeiger, ozeiger<br />
real :: temp<br />
real :: pivot ! Pivotelement<br />
pivot = array(1)<br />
uzeiger = 0<br />
ozeiger = size(array) + 1<br />
do<br />
ozeiger = ozeiger - 1<br />
do<br />
if (array(ozeiger) = pivot) exit<br />
uzeiger = uzeiger + 1<br />
end do<br />
if (uzeiger < ozeiger) then<br />
! array(uzeiger) und array(ozeiger) vertauschen<br />
temp = array(uzeiger)<br />
array(uzeiger) = array(ozeiger)<br />
array(ozeiger) = temp<br />
else<br />
iq = ozeiger<br />
return<br />
endif<br />
end do<br />
end subroutine partition<br />
20
Anhang A: Titel von Anhang 1<br />
! Der Zufallsgenerator füllt in einer DO-Schleife das Test-Array<br />
! mit <strong>der</strong> im Hauptprogramm übergebenen Länge sukzessive mit<br />
! Werten.<br />
subroutine zufall(ein_array, laenge)<br />
integer, intent(in) :: laenge ! Eingabe<br />
real, intent(out), dimension(:) :: ein_array ! Ausgabe<br />
real x ! Zufallszahl<br />
do z = 1, laenge<br />
call random_number(harvest=x) ! Zufallsgeneratorfunktion<br />
ein_array(z) = x<br />
end do<br />
end subroutine zufall<br />
end module qsort_modul<br />
program Quick_Sort ! Hauptprogramm<br />
use qsort_modul<br />
integer :: startzeit, endzeit, rate<br />
real :: zeit<br />
! laenge ist die Anzahl <strong>der</strong> zu sortierenden Werte<br />
integer, parameter :: laenge = 2000000<br />
real, dimension(laenge) :: ein_array<br />
! Aufruf <strong>der</strong> Zufalls-Subroutine, um das Test-Array mit <strong>der</strong><br />
! angegebenen Zahl an Elementen zufällig zu füllen<br />
call zufall(ein_array, laenge)<br />
! Für die Performance-Messung wird vorher die Systemzeit<br />
! gemessen, rate = 1000 gibt an, dass <strong>der</strong> Zähler 1000mal<br />
! pro Sekunde hochgezählt werden soll.<br />
rate = 1000<br />
call system_clock(count_rate=rate)<br />
call system_clock(count=startzeit)<br />
! Aufruf <strong>der</strong> rekursiven QuickSort-Subroutine<br />
call qsort_sub(ein_array)<br />
! Zeitmessung nach dem Sortieren und Differenzermittlung<br />
call system_clock(count=endzeit)<br />
zeit = (endzeit - startzeit) / real(rate)<br />
print *, "Sortiert: ", ein_array<br />
print *, "In ", zeit, " Sekunden"<br />
end program Quick_Sort<br />
21
Literaturverzeichnis<br />
[Ge91] Wilhelm Gehrke: Fortran 90: Referenz-Handbuch, Hanser-Verlag, 1991.<br />
[UH84] Regionales Rechenzentrum <strong>für</strong> Nie<strong>der</strong>sachsen (RRZN), Universität<br />
Hannover (Hrsg.): <strong>FORTRAN</strong> 77 Sprachumfang, Hannover, 1984.<br />
[CS70] Harry L. Colman, Clarence Smallwood: Fortran – Problem-orientierte<br />
Programmiersprache, KUNST UND WISSEN Erich Bieber, Stuttgart, 6.<br />
Aufl., 1970.<br />
[Gr99] G. Groten: Fortran 90/95; Kurs <strong>für</strong> die Ausbildung von MTAs,<br />
http://www.fz-juelich.de/zam/docs/bhb/bhb_html/d0124/, Datum:<br />
2004-05-02, Forschungszentrum Jülich, 1999.<br />
[OW96] Thomas Ottmann, Peter Widmayer: Algorithmen und Datenstrukturen,<br />
Spektrum Akademischer Verlag, 3. Aufl., 1996.<br />
[PTVF96] William H. Press, Saul A. Teukolsky, William T. Vetterling, Brian P.<br />
Flannery: Numerical Recipes in Fortran 90 2 nd Edition, Volume 2: The art<br />
of parallel scientific computing, Cambridge University Press, 1996.<br />
[UH03] Regionales Rechenzentrum <strong>für</strong> Nie<strong>der</strong>sachsen (RRZN), Universität<br />
Hannover: Parallele Programmierung mit OpenMP, http://www.rrzn.unihannover.de/fileadmin/ful/vorlesungen/kolloquium/ss_03/open_mp.pdf,<br />
Datum: 2004-04-27, Hannover, 2003.<br />
[Sc04] Eric Scigliano: 10 Technologien, die überlebt haben, Technology Review –<br />
Das M.I.T.-Magazin <strong>für</strong> Innovation, Nr. 3 März 2004, S. 96-99.<br />
[Ku03] Herbert Kuchen: Praktische Informatik; QuickSort Quellcode,<br />
http://www.wi.uni-muenster.de/pi/lehre/SS03/info2/quicksort.java, Datum:<br />
2004-05-03