Programmieren in Fortran 90/95


  1. Fortgeschrittene Unterprogramm-Konzepte
  2. Unterprogramme als formale Parameter in anderen Unterprogrammen

    Die Programmiersprache Fortran macht es möglich, Unterprogramme von anderen Unterprogrammen aus aufzurufen.

    Im folgenden Beispiel wird z.B. eine Routine programmiert, die ein vorgegebenes Intervall in eine vorgegebene Anzahl äquidistanter Stützstellen zerlegt, die Funktionswerte einer Function des Datentyps real an der Stützstellen berechnet und über das gesamte Intervall mittelt.

    Programmiert man sich ein Unterprogramm, welches die Intervallzerlegung und die Mittelwertbildung übernimmt und lässt man sich die Funktionswerte mit einem separaten Programm berechnen, so muss das Mittelwertbildungs-Unterprogramm die Information mitgeteilt bekommen, welches externe Programm zur Funktionswert-Berechnung verwendet werden soll. Oder anderes ausgedrückt: man müsste den Unterprogrammaufruf zur Mittelwertbildung so gestalten, dass man als aktuellen Parameter den Namen einer Funktion einsetzen kann, etwa in der Art

       write(*,*) mittelwert(f,x_unten,x_oben,schritte)   
    
    wobei in der Liste der aktuellen Parameter f der Name eines externen Unterprogramms ist und die restlichen aktuellen Parameter die aktuellen Werteangaben zum Intervall enthalten.

    Will man den Mittelwert der Funktionswerte einer anderen Funktion berechnen, so kann man als aktuellen Parameter einfach den Namen der anderen Funktion (hier z.B. f1 statt f) verwenden, also

       write(*,*) mittelwert(f1,x_unten,x_oben,schritte)   
    
    Beim Unterprogrammaufruf wird ein Zeiger (pointer) auf das als aktueller Parameter aufgeführte Unterprogramm übergeben.

    Im Unterprogramm steht als Platzhalter für das beim Funktionsaufruf tatsächlich eingesetzte Unterprogramm ein formaler Parameter (im Beispielprogramm func):

    real function mittelwert (func, anfangswert, endwert, n)
    

    Wichtig: Damit Unterprogramme als formale und aktuelle Parameter beim Unterprogrammaufruf verwendet werden können, müssen bei der Datentypanmeldung für die Functions diese bei der Deklaration mit dem Attribut external versehen werden. Dies trifft sowohl auf func in der function mittelwert

    real function mittelwert (func, anfangswert, endwert, n)
    ! Unterprogramm zur Mittelwertberechung
       implicit none
       real, external :: func
       real, intent(in)       :: anfangswert, endwert
       integer, intent(in)    :: n
    
    als auch auf die Functions f und f1 im Hauptprogramm zu, da diese als aktuelle function-Parameter beim Aufruf der Function mittelwert eingesetzt werden. Deshalb müssen diese Functions im Hauptprogramm mit dem Attribut external angemeldet werden

    program external_demo
       implicit none
       real           :: mittelwert
       real, external :: f, f1
    

    wohingegen dies für die function Mittelwert nicht der Fall ist.

    Anwendungsbeispiel: external_demo.f90

    program external_demo
       implicit none
       real           :: mittelwert
       real, external :: f, f1
       
       write(*,*) 'Mittelwert  f(x)  von   [0.0,10.0] (n=3)  = ', &
                  mittelwert(f,0.0, 10.0, 3)
       write(*,*) 'Mittelwert  f1(x) von   [0.0,1.0] (n=10)  = ', &
                   mittelwert(f1,0.0, 1.0, 10)
       
    end program external_demo
    
    
    real function f(x)
    ! Die nutzerdefinierte Funktion f(x)
       implicit none
       real, intent(in) :: x 
          f  = x
       return
    end function f
    
    
    real function f1(x)      
    ! Die nutzerdefinierte Funktion f1(x)
       implicit none
       real, parameter :: pi = 3.141593
       real, intent(in) :: x 
           f1 = 2.0 * pi * x**3
       return 
    end function f1 
    
    
    real function mittelwert (func, anfangswert, endwert, n)
    ! Unterprogramm zur Mittelwertberechung
       implicit none
       real, external :: func
       real, intent(in)    :: anfangswert, endwert
       integer, intent(in) :: n
       real                :: delta, summe
       integer             :: i 
             
       delta = (endwert - anfangswert) / real(n-1)
       summe = 0.0
    
       do i = 1, n
         summe = summe + func(real(i-1)*delta)
       end do
    
       mittelwert = summe / real(n) 
       return 
    end function mittelwert
    

    Im Programm werden sowohl f als auch f1 aktuelle Function-Parameter beim Aufruf der Function mittelwert verwendet. Dabei wird z.B. bei der ersten Berechnung für die in der function f vorgegebene Funktion f(x) = x im Intervall [0.0,10.0] an drei äquidistant voneinander entfernten Stützstellen der Mittelwert der Funktionswerte berechnet. Hier also ( f(0) + f(5) + f(10) ) / 3 = 15/3 = 5.

    Bildschirmausgabe ( external_demo.erg):

     Mittelwert  f(x)  von   [0.0,10.0] (n=3)  =    5.000000    
     Mittelwert  f1(x) von   [0.0,1.0] (n=10)  =    1.745329    
    

    Der Einsatz von Unterprogrammen als formale und aktuelle Parameter hat den Vorteil, dass sich Programmpakete sehr viel universeller einsetzbar gestalten lassen und dass bei Bedarf leicht einzelne Routinen durch andere ausgetauscht werden können.

    Sollen statt Fuctions Subroutines als formale und aktuelle Parameter eingesetzt werden, so werden statt bei der Datentyp-Deklaration der function das Attribut external zu verwenden, die involvierten Subroutines als

        external < Name der Subroutine > 
    
    deklariert.

    Unix: Der Aufbau von Programmpaketen und die make-Utility

    Wie bereits erwähnt wurde, sind unter anderen die Vorteile von Unterprogrammen dass sich klar strukturierte übersichtliche Programme schaffen lassen und dass sich einzelne Unterprogrammen in ähnlichen Projekten meist gut wiederverwenden lassen. Will man vermeiden, die benötigen Unterprogramme am Ende des Hauptprogramms einkopieren zu müssen, kann man statt dessen das Konzept des Makefiles einsetzen. Hier befinden sich meist die einzelnen Programmteile (Hauptprogramm und zugehörige Unterprogramme) als eingeständige Dateien auf gleiche Hierarchie-Ebene nebeneinander. Ein sogenanntes Makefile regelt, dass die Programmeinheiten jeweils in einen sogenannten Object-Code compiliert und danach zu einem Executable miteinander gelinkt werden.

    Das Makefile gibt die Regelsätze vor, wie die einzelnen Programmeinheiten zu Objektcode compiliert und wie die Objektcodes zu einem ausfürbaren Programm verknüpft (gelinkt) werden sollen.

    Es sollen sich nun in einem Verzeichnis nur die Programmteile des Beispielprogramms befinden:

    > ls -l
    total 3
    -rw-r--r--   1 c02g00   c02g         575 Jan 28 16:54 main.f90
    -rw-r--r--   1 c02g00   c02g         132 Jan 28 16:54 f.f90
    -rw-r--r--   1 c02g00   c02g         495 Jan 28 16:54 mittelwert.f90
    

    Das Hauptprogramm ist nun: main.f90:
    ! Das Programm ermittelt mit Hilfe der function mittelwert den
    ! an n aequidistanten Stuetzstellen ermittelten mittleren Funktionswert
    ! einer Funktion f (vorgeben durch die Funktion f) im Intervall
    ! [anfangswert,endwert]
    
    
    program external_demo
       implicit none
       real :: mittelwert
       real, external :: f
    
       write(*,*) 'Der Mittelwert aus den Stuetzstellenwerten betraegt:', &
                   mittelwert(f,0.0, 10.0, 3)
                   ! f: Unterprogramm als aktueller Parameter beim Aufruf
                   ! der Function mittelwert
    
    end program external_demo
    

    Die mathematische Funktion als real function f(x): f.f90:
    real function f(x)      ! Die nutzerdefinierte Funktion
      implicit none
      real, intent(in) :: x 
      f =x 
      return 
    end function f 
    

    Die Funktion zur Berechnung des Mittelwertes als real function mittelwert( func, anfangswert, endwert, n): mittelwert.f90:
    real function mittelwert ( func, anfangswert, endwert, n)
       implicit none
       real, external      :: func       ! Unterprogramm als formaler Parameter 
       real, intent(in)    :: anfangswert, endwert
       integer, intent(in) :: n
    
       real :: delta, x0
       real :: summe = 0.0
       integer :: i 
       
       delta = (endwert - anfangswert) / real(n-1.0)
    
       do i = 1, n
         x0 = real(i-1) * delta
         summe = summe + func(x0)
       end do
    
       mittelwert = summe / real(n) 
       return 
    end function mittelwert
    

    Mit

    man make

    kann man sich unter Unix über die Make-Utility informieren. Will man sich über die bei make voreingestellten Makro-Definitionen und Regelsätze informieren, hilft einem

    make -p

    weiter.

    Eine ausgezeichnete Erklärung zur make-Utility bietet eine Seite des ZAM des Forschungszentrums Jülich. Weitere detaillierte Informationen finden sich bei D. Faulbaum (Elektronenspeichering Bessy).

    Will man ein Makefile erstellen, so erstellt man dieses in dem Verzeichnis, in dem sich nun die Programmdateien befinden.

    Man kann dieses makefile oder Makefile nennen. Das make-Utility wird aufgerufen, in dem in dem Verzeichnis, welches die Programmdateien und das Makefile enthält, an der Kommandozeile einfach nur
    make 
    
    eingegeben wird.

    Natürlich könnte man dem Makefile auch einen anderen Namen als makefile oder Makefile geben. Allerdings müsste man dann

    make -f < alternativer Name des Makefiles>
    
    aufrufen, um die Make-Utility zu starten.

    makefile für das obige Beispiel:

    gesprog: main.o f.o mittelwert.o
            f90 -o gespro main.o f.o mittelwert.o
    main.o: main.f90
            f90 -c main.f90 
    f.o: f.f90
            f90 -c f.f90
    mittelwert.o: mittelwert.f90
            f90 -c mittelwert.f90
    clean:
                    rm *.o
    cleanall:
                    rm *.o gesprog
    

    In einem Makefile werden Abhängigkeiten, Compilier und Link-Regeln definiert. Mit der Anweisung

    f.o: f.f90
            f90 -c f.f90
    
    wird im ersten Teil festgelegt, dass die Grundlage von f.o die Fortran 90 - Programmeinheit f.90 ist. In der zweiten Zeile, die unbedingt mit einem Tabulator-Zeichen beginnen muss (was hier auf der Webseite nicht sichtbar sein kann) steht die Anweisung, wie f.o erzeugt werden soll. Und zwar wird angegeben, dass f.90 mit dem f90-Compiler in Object-Code compiliert werden soll. Dass es Objectcode werden soll, regelt die Compiler-Flag -c. Dieselben Abhängigkeiten und Verfahren gelten für die beiden anderen Programmeinheiten: main.f90, dem Hauptprogramm und dem Unterprogramm aus der Datei mittelwert.f90 gemacht. Die oberste Zeile beschreibt die Abhängigkeit von hauptprogramm von den Objektcode-Dateien und die zweite Zeile gibt an, dass diese zu dem Executable hauptprogramm gelinkt werden sollten.

    Nachdem an der Kommandozeile mit

       make
    
    die Make-Utility gestartet wurde, erhält man von make die Rückmeldung, was gerade getan wird. Es erscheinen nacheinander beim obigen Beispiel die Zeilen (makefile.erg):

    f90 -c main.f90 
    f90 -c f.f90
    f90 -c mittelwert.f90
    f90 -o gesprog main.o f.o mittelwert.o
    

    Dies wären die Befehle, die man auch nacheinander an der Kommandozeile eingeben müsste, wenn man ohne die Make-Utility arbeiten wollte.
    Im Verzeichnis stehen nun zusätzlich zum Fortran-Quelltext die Object-Files. Wir der Quelltext in einem der Programmeinheiten verändert und man ruft erneut die Make-Utility auf, so wird nur noch diese Programmeinheit neu übersetzt und die Objectcode-Files neu gelinkt.

    Zum Beispiel wird nun im Hauptprogramm das Intervall, aus an 3 äquidistant voneinander entfernten Stellen (Anfangspunkt des Intervalls, Endpunkt des Intervalls und Intervallmitte) bereits bei x=6.0 beendet. Der Unterprogrammaufruf vom Hauptprogramm aus (in main.f90) lautet nun

    mittelwert(f,0.0, 6.0, 3)
    

    Als Mittelwert der Funktionswerte erwartet man (f(0)+f(3)+f(6))/3 = 3.

    Doch zunächst wollen wir noch betrachten, wie sich nun die Make-Utility verhält. Nach Eingabe von

      make 
    
    an der Kommandozeile erhält man

    f90 -c main.f90 
    f90 -o gesprog main.o f.o mittelwert.o
    

    Die Make-Utility geht also ökonomisch vor: Es werden beim wiederholten Aufruf der Make-Utility nur noch diejenigen Teile neu compiliert (und dann natürlich gelinkt), die in der Zeit seit dem letzten Aufruf der Make-Utility verändert worden sind.

    Das ausführbare Programm wird nun an der Kommandozeile gestartet

       ./gesprog 
    
    Für das gewählte Funktions- und Zahlenbeispiel erhält man erwartungsgemäß
     Der Mittelwert aus den Stuetzstellenwerten betraegt:   3.000000
    

    Ruft man

       make clean
    
    auf, so werden alle Dateien mit der Endung *.o (alle als Objectcode vorliegenden Zwischencompilierstufen) gelöscht.

       make cleanall
    
    löscht zusätzlich das vorher erzeugte Executable gesprog mit weg.

    Unix: die automatische Generierung eines universellen Makefiles

    Michael Wester stellt im Internet ein Perl-Script zur Verfügung, welches ein universelles, für individuelle Bedürfnisse noch adaptierbares Makefile erstellt. Voraussetzung ist, dass auf dem Unix-System Perl installiert sein muss. Testen Sie dies z.B. mit
      which perl
    
    Die Unix-Antwort sollte lauten
      /usr/local/bin/perl
    
    Gibt Ihnen Ihr System einen anderen Pfad an, z.B. /usr/bin/perl, so kann man dieser Pfadangabe die 1. Zeile des Perl-Scripts von Michael Wester anpassen.

    Das Perl-Script heisst makemake und lässt sich von den Seiten der University of New Mexico herunterladen.

    1. Kopieren Sie bitte makemake in das Verzeichnis, in dem sich ausschliesslich die Dateien befinden, die Sie compilieren wollen.
    2. Machen Sie bitte dieses Perl-Script für Sie ausführbar. Dies geht z.B. mit
              chmod u+x makemake
           
    3. Rufen Sie nun das Perl-Skript auf
              ./makemake gesprog
           
    Dadurch wird in Ihrem Verzeichnis ein Makefile erzeugt:

    PROG = gesprog
    
    SRCS =  f.f90 main.f90 mittelwert.f90
    
    OBJS =  f.o main.o mittelwert.o
    
    LIBS =
    
    CC = cc
    CFLAGS = -O
    FC = f77
    FFLAGS = -O
    F90 = f90
    F90FLAGS = -O
    LDFLAGS = -s
    
    all: $(PROG)
    
    $(PROG): $(OBJS)
            $(F90) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
    
    clean:
            rm -f $(PROG) $(OBJS) *.mod
    
    .SUFFIXES: $(SUFFIXES) .f90
    
    .f90.o:
            $(F90) $(F90FLAGS) -c $<
    

    In der ersten Zeile wurde hinter PROG = der von Ihnen gewüschte Name für das ausführbare Programm (Executable) festgelegt.

    Nun können Sie an der Kommandozeile die Make-Utility starten mit

    make
    
    Ausgeführt wird
    f90 -O -c f.f90
    f90 -O -c main.f90
    f90 -O -c mittelwert.f90
    f90 -s -o gesprog f.o main.o mittelwert.o 
    

    Nachdem die einzelnen Programmdateien mit dem f90-Compiler übersetzt wurden, werden die Object-Codes zum ausführbaren Programm gesprog verknüpft.

    Die Syntax des mit dem Perl-Script erzeugten Makefiles ist universeller als die Syntax im ersten Beispiel. Das 2. Makefile enthält Makros und Argumentlisten. Voreingestellt waren im Vergleich zum ersten händischen Beispiel bei der Object-Code-Generierung die Flag zur weitestgehenden Optimierung (-O) und beim Linken die Anweisung dass bestimmte symbolische Informationen nicht im Executable vorhanden sein sollen.

    Die Compiler- und Linkerflags sollten in den Makefiles den indiduellen Bedürfnissen angepasst werden. Weitere Informationen zu den Flags findet man mit

        man f90
    
    bzw. mit
        man ld
    
    Will man genauer wissen, wie Compiler und Linker arbeiten, kann man sowohl bei den F90FLAGS als auch bei den LDFLAGS die Flag -v für engl. verbose (wortreich) hinzufügen. Dann kann man auch sehen, dass beim Linken der aus dem Programmcode erzeugte Objectcode mit Systembibliotheken zum ausführbaren Programm zusammengesetzt wird.

    Achtung: wenn Sie Ihr Executable mit einem Debugger später weiter untersuchen wollen, sollte als Compilerflag -g verwendet und als Linkerflag nicht -s verwendet werden.

    f90 -O -v -c f3.f90
    /usr/lib/cmplrs/fort90/decfort90 -O -I/usr/lib/cmplrs/hpfrtl -o f3.o f3.f90 
    f90 -O -v -c main.f90
    /usr/lib/cmplrs/fort90/decfort90 -O -I/usr/lib/cmplrs/hpfrtl -o main.o main.f90 
    f90 -O -v -c mittelwert.f90
    /usr/lib/cmplrs/fort90/decfort90 -O -I/usr/lib/cmplrs/hpfrtl -o mittelwert.o mittelwert.f90 
    f90 -s -v  -o gespro f3.o main.o mittelwert.o 
    /usr/bin/cc -s -v -o gespro f3.o main.o mittelwert.o /usr/lib/cmplrs/fort90/for_main.o 
    -O4 -qlshpf -lUfor -lfor -lFutil -lm -lots -lm_c32 -lmld -lexc 
    
    /usr/lib/cmplrs/cc/ld -o gespro -s -g0 -O4 -call_shared /usr/lib/cmplrs/cc/crt0.o f3.o main.o mittelwert.o 
    /usr/lib/cmplrs/fort90/for_main.o -qlshpf -lUfor -lfor -lFutil -lm -lots -lm_c32 -lmld -lexc -lc 
    /usr/lib/cmplrs/cc/ld: 
    0.01u 0.01s 0:00 66% 0+18k 0+17io 0pf+0w 18stk+1936mem
    

    Windows: die Make-Utility beim Compaq Visual Fortran Compiler v6.6

    Beim Compaq Digital Visual Fortran Compiler Version 6.6 kann man sich ebenfalls ein Makefile erzeugen lassen und den Compiler änlich wie unter Unix von der Kommandozeile aus einsetzen.

    Hierzu kann man folgendes "Rezept" einsetzen (Verbesserungs- und Optimierungsvorschläge bitte per Mail an die unten stehende Adresse):

    1. Developer Studio starten

    2. leeres Projekt (Fortran Console Application) erzeugen und benennen
      • Menü File -> New -> Project -> Fortran Console Application -> Projektnamen einfügen (hier: testmake) -> den Speicherort für das Projekt auswählen (und "Create New Workspace und Win32-Platform" aktiviert lassen)
      • Die Frage "What kind of console application do you want to create?" mit "An empty project" beantworten.

    3. Im WorkSpace-FileBrowser-Fenster in dem "File"-Register das Projekt aufklappen und "Source Files" mit der rechten Maustaste anklicken -> "Add files to folder" wählen
      • entweder: nach und nach einzelne Programmeinheiten neu generieren bzw. aus den Verzeichnissen einfügen (ein Programmpaket darf nur ein Hauptprogramm bei beliebig vielen Unterprogrammen enthalten)

    4. Makefile erzeugen
      • in der Menuleiste: Project -> Export Makefile mit "Write dependencies when writing makefiles" wählen
      • Das von der Entwicklungsumgebung (Developer Studio) erzeugte Makefile (im Beispiel; testmake.mak) ähnelt in Struktur und Logik dem Unix-Makefile. Es lässt sich gut mit der Applikation WordPad betrachten und weiterbearbeiten (z.B. andere Compiler-Flags einbauen)
        In der Entwicklungsumgebung könnte man wie gewohnt weiterarbeiten und bei Bedarf die Compiler-Flags und die Linker-Flags über ->Projekt -> Settings modifizieren.

    5. ausführbares Programm generieren
      • Menü: Build -> Build <Name des Projekts.exe> (hier: Build testmake.exe) wählen. Die einzelnen Teilprojekte werden dann gemäß der im Makefile enthaltenen Regeln compiliert und zu einem ausführbaren Programm gelinkt.
      • Im konkreten Beispiel werden folgende Zwischenschritte ausgeführt:
        --------------------Configuration: testneu - Win32 Debug--------------------
        Compiling Fortran...
        D:\Program Files\Microsoft Visual Studio\MyProjects\testneu\mittelwert.f90
        D:\Program Files\Microsoft Visual Studio\MyProjects\testneu\f.f90
        D:\Program Files\Microsoft Visual Studio\MyProjects\testneu\main.f90
        Linking...
        
        testneu.exe - 0 error(s), 0 warning(s)
             
        Anhand der Rückmeldung sieht man, dass die drei Quelltext-Dateien compiliert und danach über den Linker miteinander verbunden wurden. Das erzeugte Executable lässt sich wie gewohnt starten.

    6. Feineinstellungen / Anpassungen (Beispiele)
      • In der Menüleiste können Sie unter Projekt -> Settings -> Fortran die voreingestellten Compiler-Flags (Project Options) modifizieren.
      • Unter Projekt -> Settings -> Link lässt sich der Name und der Speicherort des Executables einstellen (nimmt man hier keine Änderungen vor, liegt das ausführbare Progamm im Projekt-Unterordner Debug und trägt den Namen des Projekts gefolgt von der Endung .exe.
      • Das aktuelle Arbeitsverzeichnis (Working directory) lässt sich über Menü -> Project Settings -> unter "Debug" festlegen.
      • Sollten Sie hier &Auuml;derungen vorgenommen haben, empfiehlt es sich, ein aktualisiertes Makefile zu schreiben.

    7. Optional: Compilieren und Linken an der Kommandozeile

      Man kann bei Bedarf z.B. nachdem man ein Makefile erzeugt hat, das Developer Studio verlassen und an der Kommandozeile (in der DOS-Box) weiterarbeiten.

      Dazu geht man in das Verzeichnis, in dem das Projekt abgespeichert wurde und das Makefile liegt. Durch

         nmake /f <Name des Makefiles> <Name des zu erzeugenden Executables>
      

      kann man die Make-Utility unter Windows starten. Im Beispiel wäre das entsprechende Kommando

         nmake /f testmake.mak 
          
      Hat man die Default-Einstellungen nicht verändert (d.h. unter 6. keine Anpassungen vorgenommen), so wird im oben betrachteten Beispiel ein Executable mit den Namen testmake.exe im Unterordner Debug abgelegt. In dem Unterordner Debug findet sich auch der im Zwischenschritt erzeugte Objectcode. Mit
         cd Debug
         testmake.exe bzw. testmake     
          
      lässt sich das von der Make-Utility erzeugte Executable aufrufen.

      Verändert man eine Quelltextdatei im ranghöheren Projekt-Ordner (z.B. f.f90) kann man erneut

         nmake /f testmake.mak 
          
      aufrufen. Nun wird genauso wie unter Unix nur noch aus der abgeänderten Programmeinheit erneut Objectcode erzeugt und dieser mit den bereits vorliegenden Objectcode zu einem (modifizierten) Executable gelinkt.

    Windows: Der CVF-Compiler an der Kommandozeile (in der DOS-Box)

    Der Compaq Visual Fortran Compiler lässt sich auch ausserhalb der Entwicklungsumgebung (des Developer Studios) einsetzen.

    Dazu startet man ein DOS-Fenster (z.B. je nach Windows-Version findet man im Startmenü unter Programme oder Programme -> Zubehör den Eintrag "Eingabeaufforderung" oder "Command Prompt" oder ähnliches und kann damit ein Fenster starten, in dem sich MSDOS-Befehle direkt eingeben lassen. Mit

       cd < Angabe des Pfades > 
    
    kann man in das Verzeichnis wechseln, in dem der Quelltext der Fortran-Programm liegt.

    Handelt es sich nur um ein einzelnes Fortran 90/95-Programm, z.B. beispiel.f90, so kann man dieses mit

       df beispiel.f90
    
    übersetzen, linken und ein ausführbares Programm erzeugen lassen. Das Executable wird als
       beispiel.exe
    
    erzeugt. Die Ausführung lässt sich durch die Angabe Executable-Namens (beispiel.exe oder Erweiterung einfach als beispiel) starten.

    Achtung: damit vor dem ersten Aufruf des Compilers auch alle notwendigen Pfade und Makrovariablen korrekt gesetzt wurden, sollte zunächst die Datei

         DFVARS.BAT 
    
    ausgeführt worden sein. Beim erstmaligen Start der Entwicklungsumgebung geschieht dies automatisch und hinterher stehen die benötigten Einstellungen zur Verfügung.

    Ganz analog zu UNIX lassen sich auch hier die Compiler-Flags hinter dem Compiler-Aufruf angeben, z.B. um auf Bereichsüberschreitungen in Datenfeldern zu prüfen und um gleichzeitig dem Executable einen anderen Namen zuzuweisen

       df /check:bounds beispiel.f90 /exe:ausfuehrbar.exe
    

    Besteht ein Programm aus mehreren Teilen und sollen diese zu Objectcode compiliert und danach gelinkt werden, kann man dies z.B. sukzessive oder in einem Schritt tun. Für das obige Beispiel könnte man ein einem Schritt

       df main.f90 f.f90 mittelwert.f90 
    
    die einzelnen Programmteile in Objektcode compilieren, linken und zusammen mit Systembibliotheken zm Executable main.exe verbinden lassen.
    C:\temp>df main.f90 f.f90 mittelwert.f90
    Compaq Visual Fortran Optimizing Compiler Version 6.6
    Copyright 2001 Compaq Computer Corp. All rights reserved.
    
    main.f90
    f.f90
    mittelwert.f90
    Microsoft (R) Incremental Linker Version 6.00.8447
    Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
    
    /subsystem:console
    /entry:mainCRTStartup
    /ignore:505
    /debugtype:cv
    /debug:minimal
    /pdb:none
    C:\DOCUME~1\btr029\LOCALS~1\Temp\obj37.tmp
    dfor.lib
    libc.lib
    dfconsol.lib
    dfport.lib
    kernel32.lib
    /out:main.exe
    
    Soll das Executable einen anderen Namen erhalten, z.B. gesamt.exe so wird dieser am Ende angegeben
       df main.f90 f.f90 mittelwert.f90 /exe:gesamt.exe
    
    Der Vorgang liesse sich auch in mehreren Teilschritten ausführen
     
       df /compile_only /object:main.obj main.f90
       df /compile_only /object:f.obj f.f90
       df /compile_only /object:mittelwert.obj mittelwert.f90
       df /link main.obj f.obj mittelwert.obj /out:gesamt.exe
    
    Der CVF-Compiler lässt sich auch unabhängig von der Microsoft Developer Studio-Entwicklungsumgebung an der Kommandozeile einsetzen. Zum Schreiben Ihres Quellcodes genügt ein einfacher Editor z.B. das Notepad.

    Weitere Hinweise zu den Compilerschaltern, Optimierungmöglichkeiten, zum Einbinden von Bibliotheksroutinen und der Entwicklung von gemischtsprachigen Programmen aus Fortran 90/95 und C++ findet man in den Hilfeseiten des CVF.

    Windows: Der Salford FTN95-Compiler an der Kommandozeile

    Das Programm kreis.f90 soll nun mit dem Salford FTN95 - Compiler an der Kommandozeile compiliert, gelinkt und ausgeführt werden.

    Dazu wird zunächst vom Betriebssystem Windows XP oder Windows 2000 aus das Fenster mit der Eingabeaufforderung geöffnet

    In dem sich öffnenden Fenster könnten die alten DOS-Befehle eingesetzt werden, um z.B.mit

    In dem Eingabefenster wird nun mit cd in das Verzeichnis gewechselt, in dem das Programm kreis.f90 abgespeichert wurde.

    Mit folgender Befehlssequenz lässt sich ein Win32-Executable erzeugen und ausführen:

    • ftn95 kreis.f90  
      (Compilieren mit dem Salford Fortran95 Compiler, es wird aus dem Programmcode kreis.obj und aus dem Modul kreisflaeche die Datei KREISFLAECHE.MOD (Objectcode) erzeugt)

    • slink kreis.obj -file:kreis  
      (Linken des im 1. Schritt erzeugten Objectcodes mit den Betriebsystembibliotheken mit dem Salford Linker)

    • kreis  
      (Ausführen des im 2. Schritt erzeugten Executables kreis.exe)

    Alternativ bietet der Salford-Compiler die Möglichkeit, in einem Schritt die gesamte Sequenz ausführen zu lassen:

    • ftn95 kreis.f90 /link /lgo
      (Compilieren, Linken, Ausführen in einem Schritt, dabei wird die im Zwischenschritt erzeugte kreis.obj-Datei gleich wieder gelöscht, KREISFLAECHE.MOD bleibt erhalten)

    Die Compiler-Anweisung (Compilerflag) /lgo (als Abkürzung für "load and go") startet die sofortige Ausführung des Executables kreis.exe. Lässt man /lgo weg, hat man 2 Schritte:

    • ftn95 kreis.f90 /link  
      (Compilieren und Linken)
    • kreis  
      (Ausführen des im 1. Schritt erzeugten Executables kreis.exe)

    Compiler-Options und Directiven (options und include-Anweisung)

    Mit options lassen sich innerhalb des Programmcodes Anweisungen an den Compiler (Compiler-Flags) eintragen. Wie diese lauten müssen muss im Einzelfall in den Hilfeseiten des jeweiligen Compilers nachgelesen werden.

    Die im Programmtext enthaltenen Compiler-Options haben Vorrang vor den an der Kommandozeile eingegebenen oder in der Entwicklungsumgebung eingestellten Flags.

    Werden Compiler-Options verwendet, so müssen diese beim Wechsel des Compilers und der Rechnerarchitektur (z.B. von Windows zu Unix) überprüft und in der Regel an das neue System angepasst werden.

    Die Compiler-Options sind also nicht standardisiert und Code mit einer options-Anweisung ist nicht mehr universell portabel.

    Unter Windows kann man z.B. mit /silent unterdrücken, dass der Salford Fortran95 Compiler beim Übersetzen Warnings ausgibt. An der Kommandozeile würde man in diesem Fall

        ftn95 kreis.f90 /silent 
    
    schreiben. In der Plato3-Umgebung lässt sich diese Option mit Tools -> Options -> Environment -> Project templates -> in der Zeile Check z.B. statt /CHECK eintragen. Größ- oder Kleinschreibung wird nicht beachtet.

    Um evtl. auftretende Warnings während des Compilierens zu unterdrücken, könnte man - anstatt diese Flag - an der Kommandozeile oder in der Entwicklungsumgebung einzustellen, im Falle des Salford Compilers unter Windows an den Beginn des Programmcodes die Zeile

        options(silent)
    
    stellen. Natürlich könnte man auch
        options(SILENT)
    
    oder
        OPTIONS(SILENT)
    
    schreiben. Der sonst zu den Flags gehörende / fällt auf jedem Fall in der Programmcode-Version weg. Weitere gewüschte Optionen lassen sich hinter durch Kommata getrennt hinzufügen.

    Mit der Compiler-Directive include lassen sich während des Compilierens Teile von auf externen Dateien ausgelagerten Quelltexten einbinden. include-Anweisungen dürfen bei Bedarf für alle Stellen des Programmcodes eingesetzt werden. Über include eingebundenene Programmteile dürfen wiederum include-Anweisungen enthalten. Die maximale Schachtelungstiefe ist dabei 10.

    Im folgenden Beispiel befindet sich in der Datei kreisflaeche_mod.f90 der Quelltext für das Modul kreisflaeche.

    module kreisflaeche
       implicit none
       save
       real, parameter :: pi = 3.141593
       contains 
           real function area_kreis (r)
              implicit none
              real, intent(in) :: r
              
              area_kreis = pi * r * r
           return
           end function area_kreis     
    end module kreisflaeche
    

    Der Inhalt der Datei kreisflaeche_mod.f90 wird im Programm kreis2.f90 an der Stelle im Programm, an welcher sonst im Programmcode die Module stehen, eingebunden.

    options(silent)    ! Salford FTN95-Compiler-Directive:
                       ! waehrend der Compilierung werden Warnings unterdrueckt
    
    include "kreisflaeche_mod.f90"
    
    program kreis
       use kreisflaeche
       
       implicit none
       real :: radius
       real, external :: volume_kugel
    
       write(*,'(1X,A$)') 'Geben Sie den Radius ein: '
       read(*,*) radius
       
       write(*,*) 'Die Flaeche des Kreises betraegt: ', area_kreis(radius)
       write(*,*) 'Der Umfang des Kreises betraegt:  ', 2.0 * pi * radius
       
    end program kreis
    

    Sind weitere Teile eines Programmcodes auf externe Dateien ausgelagert, so sind diese an der entsprechend richtigen Stelle mit include einzubinden.

    Der Dateinamen hinter include ist als Zeichenkette, d.h. in einfache oder doppelte Anführungszeichen eingeschlossen, anzugeben. Falls die einzuschließende Datei nicht im gleichen Verzeichnis wie der Programmtext stehen sollte, muss der Pfad, der zur Datei führt, mit angegeben werden.

    Windows: Makefiles für den Salford FTN95-Compiler

    Das bereits bekannte und schon mehrfach verwendete Programm zur Berechnung von Fläche und Umfang eines Kreises sowie des Volumes einer Kugel wurde in 3 Teile zerlegt:

    Wie schon vorher wird das Modul im Hauptprogramm über die Compiler-Directive
        include "kreisflaeche_mod.f90"
    eingebunden.

    Diesmal müssen jedoch Hauptprogramm und Unterprogramm separat in Objectcode übersetzt und zusammen mit den Betriebssystem-Bibliotheken zu einem ausführbaren Programm verlinkt werden. Per Hand kann man dies an der Kommandozeile mit 4 Befehlen durchführen lassen:

    • Compilieren:
      • ftn95 kreis4.f90
      • ftn95 volume_kugel.f90
    • Linken:
      • slink kreis4.obj volume_kugel.obj -file:kreis
    • Ausführen:
      • kreis

    Besonders bei größeren Programmpaketen, die aus einer Vielzahl an Einzelbestandteilen bestehen, kann der Vorgang sehr viel unübersichtlicher und umständlicher werden.

    Jedoch gibt es auch hier eine gute Nachricht: auch unter Windows ist es inzwischen ähnlich wie unter Unix möglich, compiler- und progammabängige Makefiles zu erzeugen, mit denen sich die Schritte des Compilierens und Linkens automatisieren lassen.

    Im Falle des Salford FTN95 - Compilers könnte das Makefile makefile (Default-Name für ein Makefile) folgendermaßen aussehen:

    kreis4.exe: kreis4.obj volume_kugel.obj
                slink kreis4.obj volume_kugel.obj -file:kreis
    
    kreis4.obj: kreis4.f90
                ftn95 kreis4.f90 /check
    
    volume_kugel.obj: volume_kugel.f90
                ftn95 volume_kugel.f90 /check
    

    Analog zu den Makefiles unter Unix werden jeweils in einer Zeile Abhängigkeiten definiert, und in der folgenden Zeile, was zu tun ist. Die Abfolge beginnt mit dem Gesamtschritt und gliedert sich sukzessive in Einzelschritte.

    Zum Beispiel bedeuten die Zeilen

    kreis4.exe: kreis4.obj volume_kugel.obj
                slink kreis4.obj volume_kugel.obj -file:kreis
    

    dass das ausführbare Programm kreis4.exe von den Objectcode-Dateien kreis4.obj und volume_kugel.obj abhängt. Die Zeile

                  slink kreis4.obj volume_kugel.obj -file:kreis
    
    enthält die Vorschrift wie kreis4.exe zu generieren wäre. Mit
                  slink kreis4.obj volume_kugel.obj
    
    würde das Executable kreis4.exe tatsächlich erzeugt. Jedoch besagt der Zusatz
                                                    -file:kreis
    
    dass das Executable den Namen kreis.exe tragen soll. Die beiden folgenden Blöcke definieren analog, von was die beiden Objectcode-Dateien abhängen und wie sie generiert werden sollen.

    Der Aufruf des Makefiles erfolgt für den Salford FTN95 an der Kommandozeile aus dem Verzeichnis heraus, in dem sowohl Makefile als auch die Quelldateien liegen müssen, mit

       mk32     
    

    Sollte das Makefile einen anderen Namen als makefile tragen, so würde entsprechend

        mk32 -f < Name des Makefiles >

    an der Kommandozeile verwendet werden können, um die Umsetzung der im Makefile geschriebenen Anweisungen, wie die einzelnen Programmteile compiliert und gelinkt werden sollen, zu starten.

    Drei zusätzliche Hinweise:

    Ähnlich wie unter Unix lässt sich auch hier ein Makefile mit Hilfe eines zugrundeliegenden generellen Syntax allgemeingültiger und kompakter formulieren.

    In dem File default.mk (Default-Name für die generalisierten Make-Syntax-Regeln beim Salford FTN95-Compiler) werden die allgemeinen Regelsätze zum Compilieren und Linken abgelegt:

    .SUFFIXES: .f90 .obj .exe
    
    OPTIONS=  
    
    OBJFILES= 
    
    
    .f90.obj:
               ftn95 $< $(OPTIONS)
    
    .obj.exe:    
               slink $(OBJFILES) -FILE:$@      
    

    Das zusätzlich notwendige Makefile makefile

    OPTIONS=   /check
    
    OBJFILES=  kreis4.obj \
               volume_kugel.obj
    
    kreis4.exe: $(OBJFILES)         
    

    ist nun sehr kompakt und bei Bedarf leicht anzupassen. Durch den Aufruf von

         mk32
    
    an der Kommandozeile aus dem Verzeichnis heraus, in dem sich sowohl default.mk, das neue makefile sowie die Quelldateien kreis4.f90 und volume_kugel.f90 befinden müssen, werden die Dateien der Endung kreis4.f90 und volume_kugel.f90 mit dem ftn95 unter Berücksichtigung der Compiler-Flag /check in Objectcode compiliert. Aus den Objectcode-Files kreis4.obj und volume_kugel.obj wird mittels des Linkers slink zusammen mit den notwendigen Betriebssystembibliotheken das Executable kreis4.exe erzeugt.

    Allgemeines zu Numerischen Bibliotheken ("Numerical Libraries")

    Durch den Einsatz von numerischen Bibliotheken lassen sich häufig die Entwicklungszeiten für Programme zur Lösung numerischer Probleme erheblich reduzieren. Im Rahmen numerischer Bibliotheken stellen Wissenschaftler oder Firmen die von Ihnen entwickelten numerischen Routinen zur Lösung typischer Fragestellungen zur Verfügung. Es gibt z.B. fertig entwickelte Routinen für

    Prinzipiell lassen sich 2 Arten numerischer Bibliotheken unterscheiden:

    Bekannte freie Bibliotheken sind z.B.:

    Häufig eingesetzte kommerzielle Bibliotheken sind u.a.:

    Beide Hersteller vertreiben Ihre Produkte für eine Vielzahl an Rechnerarchitekturen und Compiler-Herstellern (u.a. auch für Vektor- und Parallelrechner) und bieten extrem gut ausgereiften Code an.

    Der Nachteil der kommerziellen Bibliotheken ist zum einen, dass sie Geld kosten (wobei wir an der Universität Bayreuth eine Campuslizenz der NAG-Libraries zur Verfügung haben, so dass die NAG-Libraries an jedem Lehrstuhl zu minimalen Kosten eingesetzt werden können) und zum anderen, dass der Quellcode der kommerziellen numerischen Libraries nicht eingesehen werden kann und aus Know-How-Gründen nur in einer vorcompilierten Form verkauft wird.

    Sowohl bei den kommerziellen als auch den freien Libraries sind die Routinen sehr ausgereift. Die Schnittstellen zu den Unterprogramm-Routinen sind sehr gut dokumentiert, so dass man für die meisten wissenschaftlichen Probleme, solange sie sich in eine Form bringen lassen, die einem "Standard"-Problem mit existierender fertig entwickelter Bibliotheks-Routine entspricht, mittels der Library sehr schnell und ohne größeren eigenen Programmieraufwand zu einer sauberen Lösung kommen kann.

    Wie gut die mit den vorgefertigen Routinen gewonnenen Ergebnisse sind, muss natürlich im Einzelfall von dem Forscher genauestens geprüft werden. Ist das Ergebnis positiv, hat sich der Wissenschaftler durch den Einsatz der numerischen Libraries eine Menge an Entwicklungs- und Programmierzeit erspart.

    Ist die wissenschaftliche Fragestellung allerdings so beschaffen, dass sie nicht mit vorgefertigten Routinen bearbeitet werden kann, besteht vielleicht noch die Möglichkeit, auf den Source-Code der freien Libraries so zu umzuarbeiten, dass damit die vorliegende Fragestellung gelöst werden kann oder es muss tatsächlich eigener Code zur Lösung der speziellen Fragestellung entwickelt werden.

    Beispiel zum Einbinden der NAG-Libraries unter Unix

    Unter http://btrcx1.cip.uni-bayreuth.de/fl90/un.html finden Sie die Einstiegs-Dokumentation zu den auf der btrcx1 installierten NAG-Libraries.

    Dokumentation: http://www.nag.co.uk/numeric/FN/manual/html/FNlibrarymanual.asp

    Das Softwarepaket ist größtenteils installiert in dem Verzeichnis

    /usr/local/src/nagfl90/fndau04db
    
    Die Beispiele finden sich im Unterverzeichnis examples und sind identisch mit den auf der Website compilierten.

    Die Beispiele (z.B. dasjenige zu nag_quad_1d_ex01 lassen sich mit

    nagexample nag_quad_1d_ex01
    
    kopieren, compilieren und ausführen.

    Ausgeführt wird in dem Beispiel

    Copying nag_quad_1d_ex01.f90 to current directory
    cp /usr/local/src/nagfl90/fndau04db/examples/source/nag_quad_1d_ex01.f90 .
    
    Compiling and linking nag_quad_1d_ex01.f90 to produce executable file a.out
    f95 -I/usr/local/lib/fl90_modules nag_quad_1d_ex01.f90 -lnagfl90
    
    Running a.out
    
    a.out
     Example Program Results for nag_quad_1d_ex01
    
     a  - lower limit of integration =     0.0000
     b  - upper limit of integration =     6.2832
     result - approximation to the integral = -2.54326
    
    Bei dem Beispielprogramm nag_quad_1d_ex01.f90

        MODULE quad_1d_ex01_mod
    
          ! .. Implicit None Statement ..
          IMPLICIT NONE
          ! .. Default Accessibility ..
          PUBLIC
          ! .. Intrinsic Functions ..
          INTRINSIC KIND
          ! .. Parameters ..
          INTEGER, PARAMETER :: wp = KIND(1.0D0)
          ! .. Local Scalars ..
          REAL (wp) :: pi
    
        CONTAINS
    
          FUNCTION f(x)
    
            ! .. Implicit None Statement ..
            IMPLICIT NONE
            ! .. Intrinsic Functions ..
            INTRINSIC SIN, SIZE, SQRT
            ! .. Array Arguments ..
            REAL (wp), INTENT (IN) :: x(:)
            ! .. Function Return Value ..
            REAL (wp) :: f(SIZE(x))
            ! .. Executable Statements ..
            f = x*SIN(30.0_wp*x)/SQRT(1.0_wp-x*x/(4.0_wp*pi*pi))
    
          END FUNCTION f
    
        END MODULE quad_1d_ex01_mod
    
        PROGRAM nag_quad_1d_ex01
    
          ! Example Program Text for nag_quad_1d
          ! NAG fl90, Release 4. NAG Copyright 2000.
    
          ! .. Use Statements ..
          USE nag_examples_io, ONLY : nag_std_out
          USE nag_math_constants, ONLY : nag_pi
          USE nag_quad_1d, ONLY : nag_quad_1d_gen
          USE quad_1d_ex01_mod, ONLY : wp, f, pi
          ! .. Implicit None Statement ..
          IMPLICIT NONE
          ! .. Local Scalars ..
          REAL (wp) :: a, b, result
          ! .. Executable Statements ..
          WRITE (nag_std_out,*) 'Example Program Results for nag_quad_1d_ex01'
    
          pi = nag_pi(0.0_wp)
          a = 0.0_wp
          b = 2.0_wp*pi
    
          CALL nag_quad_1d_gen(f,a,b,result)
    
          WRITE (nag_std_out,'(/,1X,A,F10.4)') &
           'a  - lower limit of integration = ', a
          WRITE (nag_std_out,'(1X,A,F10.4)') 'b  - upper limit of integration = ', b
          WRITE (nag_std_out,'(1X,A,F9.5)') &
           'result - approximation to the integral =', result
    
        END PROGRAM nag_quad_1d_ex01
    

    handelt sich um die Integration einer Funktion f

    2*x*sin(30*x)/(
4-x^2/Pi^2)^(1/2)

    die in dem Programm in dem Modul quad_1d_ex01_mod festgelegt und an die NAG-Integrationsroutine durch
        CALL nag_quad_1d_gen(f,a,b,result)
    
    übergeben wird. a und b sind die Integrationsgrenzen und result entspricht dem von der NAG-Routine ermittelten Wert des Integrals.

    Ob die NAG-Routine richtig gearbeitet hat, lässt sich z.B. mit Maple überprüfen.

    Bei der Compilierung des Programms muss das Verzeichnis, über das die Modul-Definitionen der NAG-Routinen zugänglich sind, eingebunden und die eigentliche NAG-Library (diese liegt unter /usr/lib als libnagfl90.a) gelinkt werden. Dies geschieht über

        f95 -I/usr/local/lib/fl90_modules nag_quad_1d_ex01.f90 -lnagfl90
    
    Mit diesem Befehl (natürlich geht auch f90 statt f95) würden Sie kompilieren, sobald Sie Änderungen an Ihrem Programm vorgenommen haben.

    Ein ergänzender Hinweis:
    Falls Sie auf der btrcx1 die Beispiele nachvollziehen wollen, so wird der letzte Befehl von nagexample zunächst nicht umgesetzt. Grund ist, dass auf dem Rechner in der tcsh-Shell der lokale Pfad nicht mit im Suchpfad eingeschlossen ist. Sie können dies nachholen, indem Sie an der Kommandozeile

       setenv PATH .:$PATH
    
    eingeben. Dann können Sie Ihr Executable direkt mit
       a.out
    
    aufrufen und brauchen nicht mehr das aktuelle Verzeichnis über
       ./a.out
    
    zu referenzieren.

    Verwenden der NAG-Libraries mit dem Salford FTN95 - Compiler unter Windows

    Beim Start der Anwendung werden über eine Batch-Datei die Umgebungsvariablen sowohl für den Compiler als auch für die Libraries gesetzt. Mit

        cd <Name eines Unterverzeichnises>
    
    können Sie bei Bedarf in ein von Ihnen angelegtes Unterverzeichnis wechseln.

    Mit

        mkdir <Name eines neuen Unterverzeichnises>
        cd <Name des neuen Unterverzeichnises>
    
    können Sie ggfs. ein neues Unterverzeichnis anlegen und in diesen wechseln. Zum Beispiel
    y:\>mkdir nag_test
    y:\>cd nag_test
    

    Sie können nun beispielsweise ein von NAG zur Verfügung gestelltes Beispielprogramm in das von Ihnen gewählte aktuelle Verzeichnis kopieren und ausführen lassen. Unter Windows geht dies z.B. für das Beispiel nag_quad_1d_ex01 (weitere Details s.o.) mit

        nagex_dll nag_quad_1d_ex01 
    
    Das Beispielprogramm wird in das aktuelle Verzeichnis kopiert, compiliert und ausgeführt.

    Konkret sieht dies in der DOS-Box so aus:

    Y:\nag_test>nagex_dll nag_quad_1d_ex01
            1 Datei(en) kopiert.
    
    Compile and link  nag_quad_1d_ex01
    Using ftn95 nag_quad_1d_ex01.f90 /LINK /LIBR "P:\NAG\FN04\FNW3204DS\bin\nagfl90.
    dll"
    
    [FTN95/Win32 Ver. 4.6.0 Copyright (C) Salford Software Ltd 1993-2004]
         Licensed to:  Personal Edition User
         Organisation: www.silverfrost.com
    
        PROCESSING MODULE  [ FTN95/Win32 v4.6.0]
            NO ERRORS  [ FTN95/Win32 v4.6.0]
        NO ERRORS  [ FTN95/Win32 v4.6.0]
        NO ERRORS  [ FTN95/Win32 v4.6.0]
    Creating executable: nag_quad_1d_ex01.EXE
    
    Running nag_quad_1d_ex01.exe and redirecting output to nag_quad_1d_ex01.r
    

    Das Executable wurde ausgeführt und das Ergebnis in die Datei nag_quad_1d_ex01.r geschrieben. Hinterher wurde allerdings nag_quad_1d_ex01.EXE gleich wieder gelöscht:

    y:\nag_test>dir
    
     Datenträger in Laufwerk Y: ist USR
     Datenträgernummer: 84B4-EF26
    
     Verzeichnis von Y:\nag_test
    
    18.03.2005  10:06       <DIR>          .
    18.03.2005  10:06       <DIR>          ..
    11.04.2003  06:07                1.815 nag_quad_1d_ex01.f90
    18.03.2005  10:07                  195 nag_quad_1d_ex01.r
                   2 Datei(en)          2.010 Bytes
                   2 Verzeichnis(se),      95.227.904 Bytes frei
    

    In der DOS-Box kann man sich mit type <Name eines Programms> den Inhalt von ASCII-Dateien anzeigen lassen:

    Y:\nag_test>type nag_quad_1d_ex01.r
     Example Program Results for nag_quad_1d_ex01
    
     a  - lower limit of integration =     0.0000
     b  - upper limit of integration =     6.2832
     result - approximation to the integral = -2.54326
    

    Aus dem obigen Beispiel kann man ableiten, welcher Befehl zum Compilieren und Linken - auch für die selbstentwickelten Programme - eingesetzt werden muss:

    ftn95 <Name der Fortran90/95-Datei> /LINK /LIBR %NAGFL90DLL%   
    

    %NAGFL90DLL% ist die NAG-Umgebungsvariable mit der Pfadangabe zu den dynamisch zu linkenden Fortran90-Libraries. Falls Sie bei sich auf dem PC eine lokale Installation der NAG-Libraries für den Salford-Compiler vornehmen, wird der Wert dieser Umgebungsvariablen entsprechend vorbesetzt.

    Mit

       ftn95 <Name der Fortran90/95-Datei> /LINK /LIBR %NAGFL90DLL%
    
    kann man installationsunabhängig mit den Salford FTN95-Compiler bei installierten NAG-Libraries (für den Salford FTN95 benötigt man die Version FNW3204DS bei anderen Compilern andere) compilieren und linken.

    Y:\nag_test>ftn95 nag_quad_1d_ex01.f90 /LINK /LIBR %NAGFL90DLL%
    [FTN95/Win32 Ver. 4.6.0 Copyright (C) Salford Software Ltd 1993-2004]
         Licensed to:  Personal Edition User
         Organisation: www.silverfrost.com
    
        PROCESSING MODULE  [ FTN95/Win32 v4.6.0]
            NO ERRORS  [ FTN95/Win32 v4.6.0]
        NO ERRORS  [ FTN95/Win32 v4.6.0]
        NO ERRORS  [ FTN95/Win32 v4.6.0]
    Creating executable: nag_quad_1d_ex01.EXE
    

    und das Executable ausführen lassen:

    Y:\nag_test>nag_quad_1d_ex01
     Example Program Results for nag_quad_1d_ex01
    
     a  - lower limit of integration =     0.0000
     b  - upper limit of integration =     6.2832
     result - approximation to the integral = -2.54326
    

    Die Ausgabe erfolgt hier auf der Standardausgabe (in der aktuellen DOS-Box), könnte jedoch mit Hilfe eines "Grö&slig;er"-Zeichens in eine Datei umgeleitet werden, z.B.

          nag_quad_1d_ex01 > nag_quad_1d_ex01.dat
    
    Analog wie unter Unix kann man auch unter DOS statt von der Standardeingabe (der Tastatur) aus einer Datei Werte einlesen (Eingabeumleitung). Dies lässt sich z.B. gut mit dem NAG-Example zum Lösen linearer Gleichungssysteme ausprobieren (nag_gen_lin_sys_ex01).

    Y:\>mkdir nag_lin_glsys
    
    Y:\>cd nag_lin_glsys
    
    Y:\nag_lin_glsys>nagex_dll nag_gen_lin_sys_ex01
            1 Datei(en) kopiert.
            1 Datei(en) kopiert.
    
    Compile and link  nag_gen_lin_sys_ex01
    Using ftn95 nag_gen_lin_sys_ex01.f90 /LINK /LIBR "P:\NAG\FN04\FNW3204DS\bin\nagf
    l90.dll"
    
    [FTN95/Win32 Ver. 4.6.0 Copyright (C) Salford Software Ltd 1993-2004]
         Licensed to:  Personal Edition User
         Organisation: www.silverfrost.com
    
        NO ERRORS  [ FTN95/Win32 v4.6.0]
    Creating executable: nag_gen_lin_sys_ex01.EXE
    
    Running nag_gen_lin_sys_ex01.exe and redirecting output to nag_gen_lin_sys_ex01.r
    
    Y:\nag_lin_glsys>dir
     Datentraeger in Laufwerk Y: ist USR
     Datentraegernummer: 84B4-EF26
    
     Verzeichnis von Y:\nag_lin_glsys
    
    18.03.2005  11:22       <DIR>          .
    18.03.2005  11:22       <DIR>          ..
    11.04.2003  06:05                  363 nag_gen_lin_sys_ex01.dat
    11.04.2003  06:06                1.770 nag_gen_lin_sys_ex01.f90
    18.03.2005  12:20                  252 nag_gen_lin_sys_ex01.r
                   3 Datei(en)          2.385 Bytes
                   2 Verzeichnis(se),      95.191.040 Bytes frei
    
    Y:\nag_lin_glsys>type nag_gen_lin_sys_ex01.f90
        PROGRAM nag_gen_lin_sys_ex01
    
          ! Example Program Text for nag_gen_lin_sys
          ! NAG fl90, Release 4. NAG Copyright 2000.
    
          ! .. Use Statements ..
          USE nag_examples_io, ONLY : nag_std_in, nag_std_out
          USE nag_gen_lin_sys, ONLY : nag_gen_lin_sol
          ! .. Implicit None Statement ..
          IMPLICIT NONE
          ! .. Intrinsic Functions ..
          INTRINSIC KIND
          ! .. Parameters ..
          INTEGER, PARAMETER :: wp = KIND(1.0D0)
          ! .. Local Scalars ..
          INTEGER :: i, n
          REAL (wp) :: bwd_err, fwd_err, rcond
          CHARACTER (1) :: trans
          ! .. Local Arrays ..
          REAL (wp), ALLOCATABLE :: a(:,:), b(:)
          ! .. Executable Statements ..
          WRITE (nag_std_out,*) 'Example Program Results for nag_gen_lin_sys_ex01'
    
          READ (nag_std_in,*)          ! Skip heading in data file
          READ (nag_std_in,*) n
          READ (nag_std_in,*) trans
    
          ALLOCATE (a(n,n),b(n))       ! Allocate storage
    
          READ (nag_std_in,*) (a(i,:),i=1,n)
          READ (nag_std_in,*) b
    
          ! Solve the system of equations
    
          CALL nag_gen_lin_sol(a,b,trans=trans,bwd_err=bwd_err,fwd_err=fwd_err, &
           rcond=rcond)
    
          WRITE (nag_std_out,*)
          WRITE (nag_std_out,'(1X,''kappa(A) (1/rcond)''/2X,ES11.2)') 1/rcond
          WRITE (nag_std_out,*)
          WRITE (nag_std_out,*) 'Solution'
          WRITE (nag_std_out,'(4X,F9.4)') b
          WRITE (nag_std_out,*)
          WRITE (nag_std_out,*) 'Backward error bound'
          WRITE (nag_std_out,'(2X,ES11.2)') bwd_err
          WRITE (nag_std_out,*)
          WRITE (nag_std_out,*) 'Forward error bound (estimate)'
          WRITE (nag_std_out,'(2X,ES11.2)') fwd_err
    
          DEALLOCATE (a,b)             ! Deallocate storage
    
        END PROGRAM nag_gen_lin_sys_ex01
    
    Y:\nag_lin_glsys>cat nag_gen_lin_sys_ex01.dat
    Example Program Data for nag_gen_lin_sys_ex01
      4                         : Value of n
      'N'                       : Value of trans
      1.80   2.88   2.05  -0.89
      5.25  -2.95  -0.95  -3.80
      1.58  -2.69  -2.90  -1.04
     -1.11  -0.66  -0.59   0.80 : End of Matrix A
      9.52
     24.35
      0.77
     -6.22                      : End of right-hand side vector b
    
    Y:\nag_lin_glsys>type nag_gen_lin_sys_ex01.r
     Example Program Results for nag_gen_lin_sys_ex01
    
     kappa(A) (1/rcond)
         1.41E+02
    
     Solution
           1.0000
          -1.0000
           3.0000
          -5.0000
    
     Backward error bound
         5.63E-17
    
     Forward error bound (estimate)
         4.69E-14
    

    Das von NAG zur Verfügung gestellte Programm soll nun dazu hergenommen werden, um eine Lösung zu folgendem Problem zu finden

    4*x+.5*y+6*z = 26.5

    7*x+y+3*z = 24

    3*x+2*y+z = 11

    Dazu braucht das Beispielprogramm nicht verändert, sondern nur mit Hilfe eines Editors (z.B. Notepad unter Windows) eine neue Eingabedatei erstellt und im aktuellen Verzeichnis abgespeichert zu werden.

    Y:\nag_lin_glsys>cat beispiel.dat
    Beispielprogramm fuer ein lineares Gleichungssystem mit 3 Variablen
      3                         : Value of n
      'N'                       : Value of trans
     4.0 0.5 6.0
     7.0 1.0 3.0
     3.0 2.0 1.0
     26.5
     24.0
     11.0
    

    Aus dem NAG-Beispielprogramm wird ein Executables erzeugt

    ftn95 nag_gen_lin_sys_ex01.f90 /LINK /LIBR %NAGFL90DLL% 
    

    Das Ergebnis mit den neuen Beispieldaten wird berechnet und in die Datei beispiel.erg geschrieben.
    ftn95 nag_gen_lin_sys_ex01.EXE < beispiel.dat > beispiel.erg
    

    Inhalt der Ausgabedatei:

     Example Program Results for nag_gen_lin_sys_ex01
    
     kappa(A) (1/rcond)
         1.08E+01
    
     Solution
           2.0000
           1.0000
           3.0000
    
     Backward error bound
         2.02E-17
    
     Forward error bound (estimate)
         9.15E-15
    

    Selbstverständlich lassen sich die NAG-Beispielprogramme (*.f90) den jeweiligen Bedürfnissen anpassen. Auf den Webseiten von NAG finden Sie die Dokumentation und wie Sie den Aufruf der numerischen Routinen an Ihre spezifische Problemstellung anpassen können.

Zurück zur Vorlesungsseite


Heidrun.Kolinsky@uni-bayreuth.de
(Dr. Heidrun Kolinsky, Rechenzentrum der Universität Bayreuth, Gebäude NW2, Raum 159, Universitätsstraße 30, D-95440 Bayreuth, Tel. 0921/55-2687)