fortran - Department of Information Systems

Transcription

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