Fortran im Wandel der Zeit

Fortran 77

Genauer betrachtet

Fortran-Compiler gibt es viele, die meisten bieten Optionen zur Wahl des Sprachstandards an. Für den Artikel wurde der GNU-Compiler gfortran verwendet. Aber auch Intel, Portland, NAG, Lahey, Absoft, IBM und andere bieten entsprechende Tools an. Sie unterscheiden sich teilweise dadurch, ob sie Variablen mit Nullen initialisieren, was bei einer Portierung schon in manchem Legacy-Projekt für Überraschungen gesorgt hat.

Der weit verbreitete Standard Fortran 77 ist eine kompakte und übersichtliche Sprache, der man ihr ursprüngliches Ziel anmerkt: mit knappen Anweisungen numerische Operationen leicht programmieren zu können. Listing 1 zeigt ein Beispielprogramm, das zwei simple Berechnungen durchführt und dafür die wesentlichen Sprachkonstrukte benutzt:

1        program simple_fortran
2 c berechne Maschinengenauigkeit:
3 x = 1.0
4 do 100
5 y = x
6 x = x/2.0
7 if (1.0+x .eq. 1.0) goto 200
8 100 continue
9 200 print*, 'Maschinengenauigkeit = ', y
10
11 c berechne Summe:
12 write(*,*) 'Bitte n eingeben:'
13 read(*,*) n
14 sum = 0.0
15 do 300 k=1, n
16 sum = sum + 1.0/k
17 300 continue
18 write(*,10), 'Summe der Kehrwerte der ersten ',
19 & n, ' natuerlichen Zahlen = ', sum
20 10 format(a,i3,2x,a,f10.2)
21 end

Listing 1: Fortran-77-Programm

Schnell aufgezählt sind die Besonderheiten von Fortran 77: Die Standardendung für Quelldateien ist .f und es wird im Quelltext nicht zwischen Groß- und Kleinschreibung unterschieden. In altem Code lassen sich oft durchgehend großgeschriebene Schlüsselwörter finden. Zudem ist die sogenannte "Fixed Form" zu nennen. Sie ist durch die besondere Bedeutung der Spalten 1 (ein beliebiges Zeichen markiert die Zeile als Kommentar, siehe Zeilen 2 und 11 in Listing 1), 2-5 für Labels (Zeilen 8,9,17,20) und Spalte 6 für eine "Continuation Mark" (das die Zeile mit der vorangehenden verbindet, siehe Zeile 19) gekennzeichnet.

Jedes kompilierbare Programm benötigt einen Block program, vergleichbar mit der main-Funktion in C, C++ oder Java. Eine weitere Modularisierung lässt sich durch Funktionen mit (function) und ohne Rückgabewert (subroutine) erreichen.

Die elementaren Kontrollstrukturen in Fortran 77 sind if-else-Konstrukte (Zeile 7 in der einfachsten Form) und die do-Schleife. Sie dient zum einen als Zählschleife, vergleichbar einem for in anderen Sprachen (Zeilen 15-17 in Listing 1). Zum anderen sind mit einem goto ein Sprung und damit beliebige Varianten von (do-)while-Schleifen möglich, wie in den Zeilen 4 bis 8 zu sehen.

Fortran ist eine Sprache mit impliziter Typisierung: Alle Variablen, die mit i bis n beginnen, sind ganzzahlig (Datentyp Integer), wie im Beispiel die Zählvariable k und die eingelesen Obergrenze der Schleife n. Alle anderen Variablen sind Gleitkommazahlen mit einfacher Genauigkeit (Real, im Beispiel x,y und sum). Variablen lassen sich explizit deklarieren, was im Sinne einer guten Programmierpraxis zu empfehlen ist.

Erst Fortran 90 führte das implicit none-Statement ein, dass die implizite Typisierung verbietet und immer verwendet werden sollte. Gleitkommazahlen in doppelter Genauigkeit sind vom Typ Double Precision oder real*8 beziehungsweise real(8), was alles äquivalent ist. In neueren Standards kommt letztere Schreibweise zum Einsatz.

In Zeile 16 findet sich eine automatische Typkonvertierung, die Fortran durchführt: Bei der Division der real-Konstanten 1.0 durch einen Integer-Wert führt Fortran eine Konvertierung in den Typ Real durch. Das entspricht dem Vorgehen in C.

Zeilen 9, 12, 18 und 19 zeigen die beiden Möglichkeiten der Ausgabe. Bei der write-Anweisung lässt sich das erste Argument zur Angabe eines Dateideskriptors nutzen, wenn in eine Datei zu schreiben ist. Analog ermöglicht der read-Befehl nicht nur das Lesen einer Standardeingabe (wie in Zeile 13), sondern zudem das aus einer Datei. Die format-Anweisung aus Zeile 20 ist ebenfalls oft in Legacy-Code zu finden. Die dort angegebene Parametersequenz kann, in Hochkommas und runden Klammern als String, auch direkt für das Label 10 als zweiter Parameter der write-Anweisung in Zeile 18 eingesetzt werden.

Ein in ähnlicher Form oft zitiertes und skurriles Beispiel für einen durch einen Tippfehler und die implizite Typisierung entstehenden Fehler zeigt Listing 2:

1        program test
2
3 do 5 K=1. 3
4 write(*,*) K
5 5 continue
6 write(*,*) do5K, d a t e
7
8 end

Listing 2: Tippfehler

In ihm steht in der do-Anweisung statt des korrekten Kommas ein Punkt. So wird aus dem Schleifenbeginn eine Zuweisung an die implizit deklarierte Variable do5K. Das continue weiter unten bewirkt daher gar nichts, es stört den Compiler aber auch nicht. Fortran ignoriert sogar Leerzeichen, was in einem Handbuch der Firma Sun [3] treffend kommentiert wird: "Consistently separating words by spaces became a general custom about the tenth century A.D., and lasted until about 1957, when FORTRAN abandoned the practice." (gefunden in [4]).

Die Ausgabe des Programms aus Listing 2 ist damit eine Knobelaufgabe. Ihre Lösung: In Zeile 3 weist das Programm der implizit deklarierten Variable do5K den Wert 1.3 zu. In Zeile 4, die jetzt eine einfache Anweisung und nicht Teil einer Schleife ist, wird der Wert der ebenfalls implizit deklarierten Integer-Variable k ausgegeben. Da sie nicht initialisiert wurde, steht in ihr das, was eben gerade dort im Speicher steht, interpretiert als ganzzahliger Wert. In Zeile 6 gibt das Programm nun den Wert von do5K aus, und aus d a t e entsteht durch Ignorieren der Leerzeichen die Variable date, implizit vom Typ Real. Sie ist uninitialisiert, daher gibt die Software an der Stelle ebenfalls den als Gleitkommazahl interpretierten Inhalt des Speichers aus. Eine Internetrecherche nach "famous Fortran bug" schreibt einem solchen Fehler sogar den Absturz der Raumsonde Mariner 1 zu, was andernorts dann wieder dementiert wird.