Fortran 77 wird abgelöst; (Teil 1)

Fortran 90: Neuer Entwurf zur Diskussion freigegeben

14.09.1990

Die im wissenschaftlich-technischen Bereich eingesetzte Programmiersprache Fortran hat eine Frischzellenkur erhalten. Karl-Heinz Rotthäuser* zeichnet in seinem dreiteiligen Beitrag nach, welche Veränderungen "Fortran 90" im Vergleich zu "Fortran 77" bringen wird. Gegen den bei der ISO erschienenen Entwurf "Draft International Standard Fortran"** kann noch bis Februar 1991 Einspruch erhoben werden.

Die genormte Programmiersprache Fortran 77 hat die radikalste und weitreichendste Veränderung ihrer Existenz durchgemacht. Fortran-Experten aller Länder, insbesondere die Mitglieder der Arbeitsgruppe X3J3 des "American National Standards Institute" (ANSI) und der Working Group 5 der "International Standardization Organisation" (ISO), haben gemeinsam einen neuen Normentwurf erarbeitet, der unter dem Titel "Fortran 90" im Juni 1990 als "Draft International Standard" zur Abstimmung eingereicht wurde.

Seit der Publikation von Fortran 77 im April 1978 wird an der Entwicklung eines neuen Entwurfes gearbeitet. Die zentrale Idee dabei war eine Modernisierung von Fortran, so daß die Sprache ihrer historischen Rolle als wichtigste Programmiersprache zur Lösung wissenschaftlich-technischer Aufgaben weiterhin gerecht werden konnte.

Anwender wollen alte Fortran-Software nützen

Eine Grundforderung an Fortran 90 war die Aufwärtskompatibilität zur gegenwärtigen Norm Fortran 77, was dadurch erreicht wurde, daß Fortran 77 komplett in Fortran 90 enthalten ist. Darüber hinaus enthält Fortran 90 Konzepte und Strukturen, die sich in "modernen" Sprachen bewährt haben.

Fortran hat sich im Laufe seiner Existenz zu seiner gegenwärtigen Gestalt als Fortran 77 in einem stetigen Prozeß entwikkelt, ist im Grunde aber dieselbe einfache und effiziente Formelsprache für wissenschaftlichtechnische Anwendungen geblieben. In den zurückliegenden Jahren wurde ein erheblicher Aufwand an Arbeit und Geld in die Entwicklung von Fortran-77-Programmen investiert, die die Anwender heute und in Zukunft nutzen wollen.

Eine solche Investition sind zum Beispiel die mathematischen Programmbibliotheken. Da viele Anwender diese Software zusammen mit moderner Hardware auch in Zukunft nutzen wollen, ist das Interesse an der Weiterentwicklung von Fortran 77 groß. So führte der Einsatz von Vektorrechnern zu der Forderung, Matrizen in Fortran 77 verarbeiten zu können. Bei dieser Überarbeitung wurde auch der Versuch unternommen, veraltete Strukturen durch Modernisierung der Sprache abzulösen - sowohl hinsichtlich der Datenstrukturen als auch hinsichtlich der Konstrukte für die Strukturierung der Programme. Folgende Sprachmerkmale verursachen die meisten Schwierigkeiten in Fortran-77-Programmen:

- Storage association: Darunter versteht man die direkte Verknüpfung von Datenobjekten mit dem physikalischen Speicher,

- Lochkarten-orientierter Quellcode,

- fehlende Datenstrukturen,

- numerische Genauigkeit, die an die Wortlänge des Prozessors gebunden ist.

Diese und weitere Mängel wurden in Fortran 90 weitgehend behoben. Veraltete Sprachmerkmale sind als "obsolescent" gekennzeichnet. Sie waren bereits in Fortran 77 redundant, werden jedoch immer noch häufig benutzt. Die wichtigsten sind: arithmetische IF-Anweisung, Alternate Return, PAUSE-Anweisung, ASSIGN- und "assigned" GO-TO- sowie assigned FORMAT-Spezifikation.

Neue Fortran-Programme sollen nur solche Sprachmerkmale verwenden, die nicht obsolescent sind. Zur Unterstützung wird der Fortran-90-Compiler die Verwendung von Sprachkonstrukten kennzeichnen, die als obsolescent eingestuft sind, insoweit dies syntaktisch ohne großen Aufwand feststellbar ist.

Matrixoperationen sind jetzt erlaubt

So ist Fortran 77 zwar vollständig in Fortran 90 enthalten, seine Bestandteile sind jedoch teilweise als "obsolescent" eingestuft.

Die wichtigsten Erweiterungen gegenüber Fortran 77 sind:

- Matrixoperationen sind erlaubt,

- Matrizen können zur Lauf zeit eingerichtet und freigegeben werden,

- verbesserte arithmetische Genauigkeit,

- Datentypen lassen sich vom Benutzer definieren (Datenstrukturen),

- Operatoren und Zuweisungen kann der Benutzer definieren,

- Modulkonzept für Daten und Prozeduren, - Zeiger,

- rekursive Prozeduren, - Ein- und Ausgabe mit Gruppennamen (NAMELIST), - erweiterter Zeichensatz, - Operationszeichen für Relationen,

- Bit-Manipulationen mit inneren Funktionen,

- ein Konzept für die Evolution der Programmiersprache:

1. lochkartenunabhängige Quellform,

2. neue Typ-Deklarationsanweisung,

3. neue Steuerkonstrukte,

4. veraltete Sprachmerkmale sollen später wegfallen.

Das Zeichen Unterstrich (-) darf in Namen verwendet werden. Kleinbuchstaben sind erlaubt und verhalten sich äquivalent zu den entsprechenden Großbuchstaben, ausgenommen in Zeichenkonstanten. Neue Sonderzeichen sind: ! " % & ; < > ? .

Diese Sonderzeichen gehören zur Syntax und werden als Operationssymbole sowie für die Separierung und Begrenzung unterschiedlicher lexikalischer Einheiten verwendet (ausgenommen sind das Fragezeichen (?) und das Dollarzeichen ($)). Beispiel für einen Namen, der maximal aus 31 Zeichen bestehen darf: TABULATOR-POSITION.

Jedes Datenobjekt in Fortran 90 gehört einem Typ an und hat zahlreiche weitere Eigenschaften (Attribute). Explizit vereinbart wird der Typ eines Datenobjektes mit der Typ-Deklarationsanweisung, deren Gestalt wie folgt geändert wurde: Typ , Liste der Attribute :: Liste der Deklarationen.

Als Typ sind alle bisherigen Vereinbarungen zugelassen: INTEGER, REAL, DOUBLE PRECISION, COMPLEX, CHARACTER und LOGICAL. Darüber hinaus kann mit dem Schlüsselwort TYPE eine Datenstruktur vereinbart werden. Für die Typen INTEGER, REAL, COMPLEX CHARACTER und LOGICAL kann zusätzlich ein Selektor (KIND = ganze Zahl) angegeben werden. Wenn er fehlt, erhält man die bisherigen Typvereinbarungen, die voreingestellt sind.

Für numerische Datentypen wird damit der Wertebereich und die arithmetische Genauigkeit gesteuert. Für den Typ CHARACTER wurde zudem das Schlüsselwort LEN (Abkürzung für LENGTH) zur Längenangabe eingeführt. Mit dem Selektor wählt man hier einen anderen Zeichencode aus.

Beispiele:

REAL :: A, B, C

INTEGER (KIND = 2) :: I_KURZ

INTEGER (KIND = 4) :: I_LANG

REAL (KIND = 4) :: R EINFACH_GENAU

REAL (KIND = 8) :: R-DOPPELT_GENAU

COMPLEX (KIND = 4) :: C_EINFACH_GENAU

COMPLEX (KIND = 8) :: C_DOPPELT_GENAU

CHARACTER (LEN 20) :: FORTRAN_TEXT

CHARACTER (KIND 2, LEN = 10) :: TEXT_MIT_UMLAUTEN

LOGICAL :: L

Die REAL-Variablen A, B und C erhalten voreingestellte Werte für Genauigkeit und Exponentenbereich, weil die expliziten Angaben (KIND-Selektor) fehlen. Für den Typ INTEGER bedeutet "KIND = 2" einen anderen Wertebereich, der in der Regel kleiner sein wird, als "KIND = 4". Bei REAL und COMPLEX legt man mit dem KIND-Selektor die Genauigkeit fest. Die Zeichenvariable FORTRAN-TEXT kann 20 Zeichen aus dem Fortran-Zeichensatz aufnehmen. Die Zeichenvariable TEXT_MIT_UMLAUTEN kann zehn Zeichen eines anderen Zeichensatzes speichern. Um welchen Zeichencode es sich dabei handelt, wird durch den KIND-Selektor bestimmt (KIND = 2), der jedoch prozessorabhängig ist. Es könnte sich in diesem Fall um die deutsche Referenzversion des ISO-7-Bit-Codes mit Umlauten handeln.

In Fortran 90 ist nur der Fortran-Zeichensatz definiert, den dazugehörigen Datentyp vereinbart man ohne KIND-Selektor. Die ganzen Zahlen für den KIND-Selektor sind frei wählbar und prozessorabhängig. Die Zeichenfolge "::" kann - abgesehen von dem Attribut PARAMETER - entfallen, wodurch die in Fortran 77 üblichen Typvereinbarungen zulässig bleiben.

Als Attribute sind erlaubt:

- PARAMETER für das Vereinbaren von Konstanten,

- DIMENSION für das Vereinbaren von Matrizen,

- POINTER für das Vereinbaren von Zeigern,

- SAVE für das Sichern der Werte.

Beispiele:

REAL, PARAMETER :: EINS 1.0, ZWEI = 2.0

INTEGER, DIMENSION (1 : 10) :: VEKTOR

Die erste Zeile definiert zwei reelle Konstanten, die zweite eine Matrix VEKTOR für ganzzahlige Werte mit den Indices 1 bis 10.

Für alle Relationen gibt es in Fortran 90 Operationszeichen, die zu den bereits vorhandenen Operatoren hinzugekommen sind. Dabei gilt folgende Zuordnung von jeweiliger Bedeutung, Operator und Operationszeichen:

Less Than .LT.

<

Less Than Or Equal To .LE.

< =

Greater Than .GT.

>

Greater Than Or Equal To .GE.

> =

Equal To .EQ.

= =

Not Equal To .NE.

/=

Eine Matrix kann in Fortran 90 als eine Einheit angesprochen werden. Operationen lassen sich sowohl mit kompletten Matrizen als auch mit Teilmatrizen (Matrixabschnitten) ausführen. Dadurch ergeben sich kürzere Programme, und die Programmierung erfolgt auf einer höheren Ebene, weil die bisherige Auflösung in Schleifen entfällt. Anwendungsprogramme lassen sich so schneller entwickeln und zuverlässiger warten.

Für den Einsatz auf modernen Vektor- und Parallelrechnern wurden neue Matrixoperationen entworfen. Diese Operationen ermöglichen auf vielen Rechnerarchitekturen eine Optimierung der Matrixverknüpfungen. Die in Fortran 77 enthaltenen arithmetischen, booleschen und Zeichenoperationen sind auch auf Matrixoperanden anwendbar.

Zuweisungen kompletter Matrizen Teilmatrizen, maskierte Matrixzuweisungen, Konstanten und Ausdrücke in Form von Matrizen sowie die Definition von Matrixfunktionen durch den Benutzer sind ebenfalls möglich. Neue innere Funktionen (Intrinsic Functions) für das Erzeugen und Manipulieren oder das Zusammenfassen und Zerlegen von Matrizen und für die Unterstützung weiterer Rechenmöglichkeiten mit Matrizen wurden hinzugefügt (zum Beispiel MATMUL für die Matrixmultiplikation, wobei das Zeichen Stern (*) nur eine elementweise Multiplikation bewirkt).

Beispiel für das Addieren der zweidimensionalen Matrizen A und B und die Zuweisung des Ergebnisses nach C:

REAL, DIMENSION (10, 10) :: A, B, C

...

C = A + B

...

- Matrizen lassen sich statisch anlegen, dabei sind nur konstante Indexgrenzen möglich.

- Matrizen können als lokale Variable mit dem Prozeduraufruf als Lebensdauer vereinbart werden. Dabei sind variable Indexgrenzen möglich, die von aktuellen Prozedurparametern abhängen (Automatik-Matrizen).

- Mit der ALLOCATE-Anweisung läßt sich den Matrizen dynamisch Speicher zuweisen, der mit der DEALLOCATE-Anweisung wieder' freigegeben werden kann. Solche Matrizen besitzen variable Indexgrenzen. In der Typ-Deklarationsanweisung läßt man die unteren und oberen Grenzen weg.

- Matrizen dürfen formale Prozedurparameter sein: Ihre innerhalb der Prozedur nicht veränderbaren, aber sonst als variabel zu betrachtenden Indexgrenzen werden vom Aufrufer bestimmt.

- Matrizen mit dem Attribut POINTER besitzen zunächst keinen eigenen Speicher. Ihre Ausdehnung wird erst durch die Assoziierung des Zeigers mit dem Ziel festgelegt.

Durch eine Folge von skalaren Werten, die von den Zeichen (/und /) eingeschlossen werden, kann eine Matrix mit dem Rang 1 (Vektor) gebildet werden.

Beispiel:

REAL, DIMENSION (4) :: X

X = (/3.2, 4.01, 6.5, 2.3/)

In diesem Beispiel wird der Matrix X ein konstanter Ausdruck zugewiesen. Ergebnis:

X(1) = 3.2, X(2) = 4.01, X(3) = 6.5,

X(4) = 2.3. Soll dieser Vektor einer mehrdimensionalen Matrix zugewiesen werden, muß die Funktion RESHAPE benutzt werden. Jeder Matrixausdruck ist als Konstruktor verwendbar; zusätzlich kann er implizite Schleifen enthalten.

Beispiel:

INTEGER l(51)

I = (/(N, N = 0, 100, 2/)

In diesem Beispiel werden der Matrix I alle geraden Zahlen von 0 bis 100 (Schrittweite ist 2) zugewiesen.

Matrixabschnitte lassen sich auswählen

Durch Triplex-Notation läßt sich jederzeit ein rechteckiger Ausschnitt aus einer Matrix auswählen.

Beispiel:

A(1: 10 : 2, 10 : 1 : -3)

Der erste Parameter der Indexliste legt den Anfangswert, der zweite den Endwert und der dritte die Schrittweite fest. Fehlt der erste Parameter, wird die Untergrenze der Dimension genommen, fehlt der zweite Parameter, wird die Obergrenze genommen und fehlt der dritte Parameter, wird als Schrittweite eins verwendet.

Beispiel:

REAL, DIMENSION (5,4,3) :: D

...

D(3:5, 2, 1:2) = RESHAPE((/1.0, 2.0, 3.0, 4.0, 5.0, 6.0/), (/3,2/))

Die Funktion RESHAPE enthält als ersten Parameter einen konstanten Konstruktor und an zweiter Stelle die Dimensionen der Matrix. Die Ergebnisvariable ist ein Matrixabschnitt, der den Rang 2 mit den Dimensionen 3 und 2 hat und aus folgenden Elementen besteht:

D(3,2,1) = 1.0 D(3,2,2) = 4.0

D(4,2,1) = 2.0 D(4,2,2) = 5.0

D(5,2,1) = 3.0 D(5,2,2) = 6.0

In der Deklaration werden Typ und Rang vereinbart, und im Falle einer Matrix fehlt die Größenangabe. Rechenoperationen mit Zeigern sind nicht erlaubt. jeder Zeiger ist disassoziiert und kann erst benutzt werden, nachdem er mit dem Speicher verknüpft wurde, was auf zweierlei Art geschehen kann:

1) Ausführung einer ALLOCATE-Anweisung,

2) Ausführung einer Zeigerzuweisung: ZEIGER = > OBJEKT.

Ein Zeiger besteht aus zwei Teilen: dem Objekt und dem Deskriptor. Wenn er in einem Ausdruck auftritt, handelt es sich um das Objekt. Tritt er in einer ALLOCATE-Anweisung oder auf der linken Seite einer Zeigerzuweisung auf, handelt es sich um den Deskriptor, auf den man selbst nicht zugreifen kann.

Beispiele:

REAL, DIMENSION(:,:),

POINTER:: IN, OUT

...

ALLOCATE(IN(-3:M, 0:9),

STAT = FEHLER)

REAL, DIMENSION(1000,1000), TARGET :: A, B

...

OUT = > A

Die erste Anweisung vereinbart die Zeiger IN und OUT (Typ REAL und Rang 2). Die ALLOCATE-Anweisung kreiert das Zeigerobjekt. Über die Variable FEHLER (Typ INTEGER) erfährt man, ob die Anweisung erfolgreich ausgeführt wurde. Der Zeiger OUT wird mit der Matrix A verknüpft und kann danach benutzt werden. Auf statische Objekte wie A können Zeiger nur dann verweisen, wenn diese das Attribut TARGET haben. Die Verknüpfung von Zeiger und Objekt wird mit NULLIFY aufgehoben.

*Karl-Heinz Rotthäuser ist wissenschaftlicher Mitarbeiter der Gesellschaft für Mathematik und Datenverarbeitung mbH in Sankt Augustin und Leiter des Arbeitskreises Fortran beim DIN.

** Zu beziehen als DIS 1539, Ausgabe 1990 - Programming Language Fortran" bei der Beuth Verlag GmbH, Postfach 11 45, 1000 Berlin 30.