Fortran90
Transcription
Fortran90
Fortran90 in Kürze Dieter an Mey, Rechenzentrum der RWTH Aachen 14. März 2001 [email protected] http://www.rz.rwth-aachen.de [/hpc] Programmiersprachen im Hochleistungsrechnen Verbreitung (persönliche Einschätzung) FORTRAN77 Fortran90/95 C C++ Java Programmiersprachen Derzeit im Hochleistungsrechnen hier genutzte Sprachen (Schätzung) Fortran77 (ext) ca. 80-90% C ca. 10-20 % (Tendenz steigend) Fortran90 selten C++ selten Meine Empfehlung: Sehen Sie sich Fortran90 an ! Fortran90 ist zu Fortran77 aufwärts kompatibel Fortran90 schließt die Möglichkeiten von C weitgehend ein Fortran90 kann auch einiges von C++ Es ist für techn.-wiss. Aufgabenstellungen häufig die geeignetere Sprache Ausgereifte Compiler stehen auf allen Plattformen zur Verfügung (Es gibt auch eine p.d. Version für Linux, basierend auf g77) Evtl. ist die Kombination von Fortran90 und C(++) zu erwägen. Fortran77 wesentliche Charakteristika Feldverarbeitung ohne Zeiger (Pointer) COMMON-Blöcke Call by Reference Kein Überlappen von beim Aufruf übergebenen Feldern Seiteneffekte Nicht vergessen! Felder werden in Fortran spaltenweise abgespeichert ! (und nicht zeilenweise wie z.B. in C) Fortran77 Feldverarbeitung, Call by Reference PROGRAM MAIN IMPLICIT REAL (A-H,O-Z) IMPLICIT INTEGER (I-N) PARAMETER (LD1=11,LD2=12,LD3=13) DIMENSION A(LD1,LD2,LD3) READ (*,*) N1, N2, N3 CALL SUB ( A, LD1, LD2, N1, N2, N3 ) ... SUBROUTINE ( A, LD1, LD2, N1, N2, N3 ) REAL A(LD1,LD2,*) DO I1=1,N1 DO I2=1,N2 DO I3=1,N3 A(I1,I2,I3) = ... END DO END DO END DO ... Fortran77 COMMON-Blöcke PROGRAM MAIN PARAMETER (LD1=11,LD2=12,LD3=13) COMMON / NAME / A(LD1,LD2,LD3) READ (*,*) N1, N2, N3 CALL SUB ( N1, N2, N3 ) ... SUBROUTINE ( N1, N2, N3 ) PARAMETER (LD1=11,LD2=12,LD3=13) COMMON / NAME / A(LD1,LD2,LD3) DO I1=1,N1 DO I2=1,N2 DO I3=1,N3 A(I1,I2,I3) = ... END DO END DO END DO ... Fortran77 COMMON-Blöcke PROGRAM MAIN INCLUDE ´defs.inc` READ (*,*) N1, N2, N3 CALL SUB ( N1, N2, N3 ) ... C defs.inc PARAMETER (LD1=11,LD2=12,LD3=13) COMMON / NAME / A(LD1,LD2,LD3) SUBROUTINE ( N1, N2, N3 ) INCLUDE ´defs.inc` DO I1=1,N1 DO I2=1,N2 DO I3=1,N3 A(I1,I2,I3) = ... END DO END DO END DO ... Fortran77 ACHTUNG! Überlappende Felder PROGRAM MAIN PARAMETER (MAX=1000000) COMMON / NAME / WORK(MAX) READ (*,*) N1, N2, N3 CALL SUB ( N1,N2,N3, WORK(1),WORK(1+N1),WORK(1+N1+N2) ) ... SUBROUTINE SUB ( N1, N2, N3, A, B, C ) REAL A(*), B(*), C(*) DO I=1,MIN( N1, N2, N3 ) ! ACHTUNG weiter darf I nicht laufen A(I) = B(I) + C(I) END DO ... Fortran77 ACHTUNG! Seiteneffekt PROGRAM MAIN CALL SUB ( 1 ) WRITE (*,*) 1 STOP END Was wird ausgegeben ? SUBROUTINE ( IEINS) IEINS=2 SUN f77: POSSIBLE ATTEMPT TO MODIFY CONSTANT RETURN END Segmentation Fault(coredump) SUN frt: 2 SGI f77/f90: 1 VPP frt: 2 HP f90: 1 LINUX g77: Memory fault(coredump) LINUX pgf77:1 LINUX pgf90:2 2 Fortran90 Ziele Einbringen von moderenen Sprachkonstrukten in Fortran77 dynamische Speicherverwaltung, Strukturen, Felder, Rekursionen, Definition von eigenen Typen, Überladen von Operatoren Standardisierung der zahlreichen proprietären Spracherweiterungen von Fortran77 Erhöhung der Programmsicherheit Module, interne Prozeduren, Schnittstellen (interfaces) Kompatibilität zu Fortran77 Komfort Fortran90 Neue Eigenschaften Feldverarbeitung Dynamische Speicherverwaltung, automatische Felder Module Prozeduren mit optionalen und Schlüsselwortparametern interne Prozeduren rekursive Prozeduren Zeiger freies Quellformat Vereinbarungen, IMPLICIT NONE abgeleitete Typen Operatorüberladung CASE-Anweisung EXIT und CYLCE zahlreiche neue Intrinsic-Funktionen neue IO-Möglichkeiten Fortran90 Obsolete Eigenschaften - Empfehlungen Arithmetisches IF DO-Schleifenparameter mit reellem Datentyp DO-Schleifenenden, die kein separates CONTINUE oder END DO besitzen ASSIGN und assigned GOTO-Anweisungen Sprung auf END IF von außerhalb des IF-Blockes Alternative RETURN-Anweisungen H- Formatbeschreiber Anstelle von INCLUDE sollten Module verwendet werden IMPLICIT NONE verwenden Anstelle von COMMON, BLOCK DATE und EQUIVALENCE sollten Module und dynamische Speicherverwaltung genutzt werden Aber: in OpenMP V1.x werden nur COMMON-Blöcke unterstützt, seit 10/2000 mit V2 auch Modele Fortran90 Programmzeilen Freies Format max. 132 Zeichen je Zeile Mehrere Befehle in einer Zeile erlaubt mit Semikolon (;) als Trennzeichen Variablenamen bis 31 Zeichen inkl. Underline (_) Kommentare hinter dem Ausrufezeichen (!) Keine überflüssigen Blanks mehr in Schlüsselworten Folgezeilen durch Undzeichen (&) am Ende der vorangehenden Zeile, die Folgezeile darf als erstes nichtleeres Zeichen ebenfalls damit (&) beginnen. Tipp Folgezeilen, die sowohl der Fortran77 als auch der Fortran90 Konvention folgen sollten je ein Undzeichen (&) am Zeilenende in Spalte 73 der vorangehenden Zeile und ein Undzeichen in der Spalte 6 der Folgezeile haben. Fortran90 Logische Ausdrücke Logische Ausdrücke Die Zeichen <, >, <=, >=, ==, /= sind ebenso wie .LT., .GT., .LE., .GE., .EQ., .NE. zu verwenden. Fortran90 Vereinbarungen Vereinbarungen IMPLICIT NONE REAL, DIMENSION(3), PARAMETER,Attribut-Liste :: a = ( /0.0,0.0,0.0/) Attribute: DIMENSION(extends) PARAMETER PUBLIC PRIVATE POINTER TARGET ALLOCATABLE INTENT(inout) OPTIONAL SAVE EXTERNAL INTRINSIC Fortran90 Verschiedenes DATA i /B‘01010101010101010101010101010101‘/ DATA i /O‘01234567‘/ DATA i /Z‘ABCDEF‘/ a = ´´ a(:5) = a(3:7) ! binär ! oktal ! hexadezimal ! leere Zeichenkette ! Zuweisung von einander überlappenden Zeichenketten Fortran90 Kontrollstrukturen - Bedingung Bedingung dürfen einen Namen erhalten name: IF ( log.exp. ) THEN block ELSE IF ( log.exp. ) THEN name block ELSE name block END IF name Fortran90 Kontrollstrukturen - Fallunterscheidung Fallunterscheidung name: SELECT CASE (3*i-j) CASE(0) name ... CASE(2,4:7) name ... CASE DEFAULT ... END SELECT name Fortran90 Kontrollstrukturen - Zählschleife Zählschleifen DO ... END DO ! Endlosschleife ! Hoffentlich gibt es eine Abbruchbedingung! DO WHILE ( log. exp.) ... END DO Den Schleifen dürfen Namen gegeben werden name: DO i = ilow, ihigh, istep ... END DO name Beenden des aktuellen Schleifendurchlaufes CYCLE name Beenden der akutellen Schleifenausführung EXIT name Fortran90 Programmeinheiten Programmeinheiten sind Hauptprogramm und externe Prozeduren, wie in Fortran77 Prozeduren sind Unterprogramme oder Funktionen Externe Prozeduren sind abgschlossene Programmeinheiten und können von außen aufgerufen werden (und müssen nicht alle in Fortran programmiert sein) NEU Module Ein Modul enthält Vereinbarungen, die in anderen Programmeinheiten genutzt werden können (USE-Anweisung, Ersatz für COMMON-Blöcke) Modulprozeduren Ein Unterprogramm, daß in einem Modul vereinbart ist, heißt Modulprozedur interne Prozeduren Ein Unterprogramm, daß in einem Hauptprogramm, einer externen Prozedur oder einer Modulprozedur vereinbart ist heißt interne Prozedur. Interne Prozeduren können nicht geschachtelt werden. Sie stehen am Ende einer Programmeinheit nach einer CONTAINS-Anweisung Fortran90 Programmeinheiten - Beispiel SUBROUTINE sub ( n, x, y, z, sum ) IMPLICIT NONE INTEGER :: n REAL, DIMENSION(100) :: x, y, z, sum sum = add ( a, b, c ) RETURN CONTAINS FUNCTION add ( a, b, c ) RESULT ( sum ) IMPLICIT NONE REAL, INTENT(IN) :: a, b, c REAL :: sum sum = a + b + c END FUNCTION add END SUBROUTINE sub Fortran90 Schnittstellenbeschreibungen Schnittstellenbeschreibungen legen die Einzelheiten der Prozedurargumente fest. (vgl. Header-Dateien in C, im Unterschied dazu müssen sie aber compiliert werden.) Zu jedem Aufrufparameter kann die Nutzungsart festgelegt und damit überprüft werden. INTERFACE SUBROUTINE sub ( n, x, y, z, sum ) INTEGER :: n REAL, DIMENSION(100), INTENT(IN) :: x, y, z REAL, DIMENSION(100), INTENT(OUT) :: sum END SUBROUTINE sub END INTERFACE Fortran90 Aufrufparameter Aufruf von Programmeinheiten mit Postions- oder Schlüsselwortparametern, Verwendung von optionalen Parametern CALL solve ( a, b, n ) CALL solve ( n=i, a=x ) SUBROUTINE solve ( a, b, n ) INTEGER, INTENT(IN) :: n REAL, INTENT(INOUT) :: a REAL, OPTIONAL, INTENT(IN) :: b Fortran90 Rekursive Prozeduren Rekursive Funktionen müssen das Ergebnis über eine explizit mit der RESULTKlausel vereinbarte Variable zurückgeben RECURSIVE FUNCTION fact(n) RESULT(res) IMPLICIT NONE INTEGER, INTENT(IN) :: n INTEGER :: res IF ( n == 1 ) THEN res = 1 ELSE res = n * fact(n-1) ENDIF END FUNCTION fact Achtung: Wenn möglich, aus Performance-Gründen rekursive Funktionen vermeiden. Fortran90 Feldverarbeitung (1) Rang (rank) eines Feldes(array): Anzahl der Dimensionen Ausdehnung (extend) einer Dimension eines Feldes: Anzahl der Elemente dieser Dim. Form (shape) eines Feldes: Vektor aller Ausdehnungen Größe (size) eines Feldes: Gesamtzahl aller Elemente Konforme (conformable) Felder haben dieselbe Form (shape) und können miteinander verknüpft werden Felder sind immer konform zu einem Skalar, dieser wird in Ausdrücken passend erweitert (broadcast) Fortran90 Feldverarbeitung (2) Beispiele REAL,DIMENSION(5,5) :: ra,rb,rc INTEGER :: id,i,j ! äquivalent ra = rb + rc * id ! SHAPE(/5,5/) and scalar ra(:,:) = rb(:,:) + rc(:,:) * id(:,:) ! SHAPE(/5,5/) and scalar ! äquivalent ra(3:5,3:4) = rb(1::2,3:5:2) + rc(1:3,1:2) ! SHAPE(/3,2/) DO j=1,2 DO i=1,3; ra(i+2,j+2) = rb(2*i-1,2*j+1) + rc(i,j) END DO END DO ra(:,1) = rb(:,1) + rb(:,2) + rc(:,3) ! SHAPE(/5/) Fortran90 Feldverarbeitung - Bedingungen WHERE ... ELSEWHERE ... END WHERE REAL, DIMENSION(100) :: x, y, z LOGICAL, DIMENSION(100) :: l ... WHERE ( z >= 1.0e-10 ) x = y / z ELSEWHERE x = 0.0e0 END WHERE ... l = z >= 1.0e-10 x = 0.0e0 WHERE ( l ) x = y/z END WHERE Fortran90 Feldverarbeitung - Rekursionen Vorsicht bei Rekursionen! (ein Schleifendurchlauf benötigt die Ergebnisse eines vorherigen) PROGRAM recursion INTEGER, PARAMETER :: n = 5 INTEGER, DIMENSION(n) :: a INTEGER :: i ! rekursive Berechnung von a(i) = a(1)+a(2)+...+a(i) DO i=2,n a(i) = a(i-1) + a(i) END DO ! Berechnung von a(i) = a(i) + a(i-1); keine Rekursion a(2:n) = a(1:n-1) + a(2:n) ! Fortran 90 Lösung (Performance ??!!) : a(2:n) = (/ (SUM(a(1:i)),i=2,n) /) END PROGRAM recursion Fortran90 Dynamische Speicherverwaltung (1) Dynamische Felder REAL, DIMENSION (:,:), ALLOCATABLE :: ra REAL :: xsum INTEGER :: n, m, status, iseed READ (*,*) n, m ! read Input matrix size ALLOCATE (ra(n,m), STAT = status) IF (status > 0) STOP 'Fail to allocate memory for allocatable array‘ iseed = 1 CALL RANDOM_SEED (PUT=iseed) CALL RANDOM_NUMBER (ra) CALL rsum ( ra, xsum ) xsum = SUM( ra ) DEALLOCATE (ra) Fortran90 Dynamische Speicherverwaltung (2) Fortsetzung SUBROUTINE rsum ( ra, xsum ) REAL, DIMENSION (:,:) :: ra REAL :: xsum INTEGER :: n, m, status, iseed xsum = 0.0d0 DO i = 1, SIZE ( ra, 1 ) DO j = 1, SIZE ( ra, 2 ) xsum = xsum + ra(i,j) END DO END DO RETURN END SUBROUTINE rsum Fortran90 Dynamische Speicherverwaltung (3) Automatische Felder SUBROUTINE sub ( n, a ) IMPLICIT NONE INTEGER :: n REAL, DIMENSION(n,n), INTENT(INOUT) :: a REAL, DIMENSION(n,n) :: work1 ! automatisch REAL, DIMENSION(SIZE(a,1)) :: work2 ! automatisch ... RETURN END SUBROUTINE sub Fortran90 Feldverarbeitung - Intrinsics (1) Reduktionen von Feldelementen ALL, ANY, COUNT, PRODUCT, SUM, MAXVAL, MINVAL, MAXLOC, MINLOC Informationen über die Form eines Feldes ALLOCATED, LBOUND, UBOUND, SHAPE, SIZE Erstellen von Feldern MERGE, PACK, UNPACK, SPREAD Umformen von Feldern RESHAPE Feldverarbeitung CSHIFT, EOSHIFT, TRANSPOSE Feldarithmetik DOT_PRODUCT, MATMUL Achtung: Die Performance der Intrinsics ist nicht immer optimal ! (z.B. besser DGEMM aus einer optimierten Blas-Bibliothek als MATMUL nehmen) Fortran90 Feldverarbeitung - Intrinsics (2) Beispiele REAL s, x(100) s = SUM ( x, MASK = x > 0.0 ) REAL, DIMENSION(-3:4) :: x INTEGER, DIMENSION(1) :: locmax x = (/1.2,3.4,5.4,11.2,1.0,3.7,1.0,1.0/) locmax = MAXLOC(x) maxval = x(LBOUND(x) + locmax(1) - 1 ) ! = (/4/) Fortran90 Abgeleitete Typen Abgeleitete Typen (derived types, Strukturen) INTEGER, PARAMETER :: male=1, female=0 TYPE person INTEGER :: ident INTEGER :: sex REAL :: salary END TYPE person TYPE (person), DIMENSION(100) :: group TYPE (person) :: boss = person(1,female,100000.0) group%sex = male ! alles Männer group%sex(27) = female ! Huhn im Korb group(1) = boss Fortran90 Operatorüberladung MODULE vector_module TYPE vector REAL :: x, y END TYPE vector INTERFACE OPERATOR (+) ! overloading operator + MODULE PROCEDURE vector_add END INTERFACE CONTAINS FUNCTION vector_add(v1, v2) TYPE (vector) :: vector_add TYPE (vector), INTENT(IN) :: v1, v2 vector_add%x = v1%x + v2%x vector_add%y = v1%y + v2%y END FUNCTION vector_add END MODULE vector_module Fortran90 Zeiger (1) Zeiger (pointer), werden nicht als Zeiger auf Speicherplätze verwendet, sondern eher als Alias-Bezeichnungen. Sie sind mit Vorsicht zu benutzen. PROGRAM linked_list TYPE node INTEGER :: value ! data filed TYPE (node), POINTER :: next ! pointer field END TYPE node INTEGER :: num, status TYPE (node), POINTER :: head, tail, current ! build up the list NULLIFY(head, tail) ! initially nullify the list (empty) PRINT *, 'Type-in an integer number to build a linked list (0 to terminate)' READ *, num ! read num from keyboard IF (num /= 0) then ! if 0 is entered, do nothing ALLOCATE(head, STAT = status) ! create the head of the list IF (status > 0) STOP 'Fail to allocate a new node' head%value = num ! give the value NULLIFY(head%next) ! point to null tail => head ! update tail of list Fortran90 Zeiger (2) ! create rest of list READ *, num ! read num from keyboard IF (num == 0) EXIT ! until 0 is entered ALLOCATE(current, STAT = status) ! create new node IF (status > 0) STOP 'Fail to allocate a new node' current%value = num ! giving the value NULLIFY(current%next) ! point to null (end of list) tail%next => current ! link to tail of list tail => current ! update tail of list END DO END IF DO ! transverse the list and print the values current => head ! make current as alias of list DO IF (.NOT. ASSOCIATED(current)) EXIT ! exit if null pointer PRINT *, current%value ! print the value current => current%next ! make current alias of next node END DO END PROGRAM linked_list Fortran90 Datentypvarianten Der Datentypvarianten (KIND) erlaubt eine Mindestanzahl von signifikanten Dezimalstellen anzufordern. Meist genügen REAL*4, REAL*8 etc. Interessanter Fall: Ein Programm wird mit oder ohne Autodouble-Option übersetzt. include ´mpif.h´ REAL, DIMENSION(:,:) :: x INTEGER :: mpi_float SELECT CASE (KIND(x)) CASE(4) mpi_float = MPI_REAL CASE(8) mpi_float = MPI_DOUBLE_PRECISION CASE DEFAULT STOP ´real kind unsupported by MPI´ END SELECT CALL MPI_SEND(x,SIZE(x),mpi_float,...) Fortran90 Ein-/Ausgabe nicht vorrückende Ein-/Ausgabeanweisung WRITE (*,´(„Eingabe? “)´,ADVANCE=´NO´) READ(*,´(I5)´) n neue OPEN-Parameter POSITION = ASIS | REWIND | APPEND | UNDEFINED ACTION = READ | WRITE | READWRITE | UNDEFINED STATUS = OLD | NEW | SCRATCH | REPLACE | UNKNOWN neue Format-Beschreiber EN (engenieerung), ES (scientific), B (binary), O (octal), Z (hex), G (generalized) NAMELIST /listname/ a, i, x READ ( unit, NML=listname) Fortran90 Literatur / Weblinks Fortran90 - Ein Nachschlagewerk, RRZN Hannover, SPR.F90 1, 8/92, im Rechenzentrum erhältlich Fortran90 - A conversion Course for Fortran77 Programmers - Student Notes http://www.mcc.ac.uk/hpc/mantec/ http://www.uni-karlsruhe.de/~Fortran90/Tutorials/Manchester Fortran95 - Fachwörterliste Englisch-Deutsch, RRZN Hannover, SPR.F95 2, 10/95 http://www.nsc.liu.se/~boein/f77to90/f77to90.html Online Tutorial Homepage von Wilhelm Gehrke mit zahlreichen weiteren Fortran-Links http://www.unics.uni-hannover.de/rrzn/gehrke Freier Fortran90-Compiler für Linux und Kommentar dazu http://www.psrv.com http://www.heise.de/ix/artikel/1998/08/068 User Notes on FortranProgramming http://SunSITE.Informatik.RWTH-Aachen.DE/fortran Weitere Links zum Thema Fortran http://www.fortranlib.com/ http://www.uni-karlsruhe.de/~Fortran90/ http://studbolt.physast.uga.edu/templon/fortran.html