15.12.2012 Aufrufe

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 ...

MEHR ANZEIGEN
WENIGER ANZEIGEN

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

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

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!