SSSSSSSS    KK        KK  RRRRRRRRRR    IIIIIIII  PPPPPPPPP    TTTTTTTT
    SSSSSSSSSS   KK       KK   RRRRRRRRRRR   IIIIIIII  PPPPPPPPPP   TTTTTTTT
   SS        SS  KK      KK    RR        RR     II     PP       PP     TT
   SS            KK     KK     RR        RR     II     PP       PP     TT
    SSS          KK    KK      RR        RR     II     PP       PP     TT
      SSSS       KKKKKKK       RRRRRRRRRRR      II     PPPPPPPPPP      TT
        SSSS     KKKKKKK       RRRRRRRRRR       II     PPPPPPPPP       TT
           SSS   KK    KK      RR    RR         II     PP              TT
             SS  KK     KK     RR     RR        II     PP              TT
   SS        SS  KK      KK    RR      RR       II     PP              TT
    SSSSSSSSSS   KK       KK   RR       RR   IIIIIIII  PP              TT
     SSSSSSSS    KK        KK  RR        RR  IIIIIIII  PP              TT
 
                               ZZZZZZZZZZZZ  UU        UU
                               ZZZZZZZZZZZZ  UU        UU
                                       ZZZ   UU        UU
                                      ZZZ    UU        UU
                                     ZZZ     UU        UU
                                    ZZZ      UU        UU
                                   ZZZ       UU        UU
                                  ZZZ        UU        UU
                                 ZZZ         UU        UU
                                ZZZ          UU        UU
                               ZZZZZZZZZZZZ   UUUUUUUUUU
                               ZZZZZZZZZZZZ    UUUUUUUU
 
   FFFFFFFF   OOOOOOOO   RRRRRRRR  TTTTTTTT RRRRRRRR      AAAAAA    NN     NN
   FFFFFFFF  OOOOOOOOOO  RRRRRRRRR TTTTTTTT RRRRRRRRR    AAAAAAAA   NN     NN
   FF        OO      OO  RR      RR   TT    RR      RR  AA      AA  NNN    NN
   FF        OO      OO  RR      RR   TT    RR      RR  AA      AA  NNNN   NN
   FF        OO      OO  RR      RR   TT    RR      RR  AA      AA  NN NN  NN
   FFFFFFFF  OO      OO  RRRRRRRRR    TT    RRRRRRRRR   AAAAAAAAAA  NN NN  NN
   FFFFFFFF  OO      OO  RRRRRRRR     TT    RRRRRRRR    AAAAAAAAAA  NN  NN NN
   FF        OO      OO  RR  RR       TT    RR  RR      AA      AA  NN  NN NN
   FF        OO      OO  RR   RR      TT    RR   RR     AA      AA  NN   NNNN
   FF        OO      OO  RR    RR     TT    RR    RR    AA      AA  NN    NNN
   FF        OOOOOOOOOO  RR     RR    TT    RR     RR   AA      AA  NN     NN
   FF         OOOOOOOO   RR      RR   TT    RR      RR  AA      AA  NN     NN
 
                                                    777777777     777777777
                                                   77777777777   77777777777
                                                            777           777
                                                           777           777
                                                          777           777
                                                      7777777       7777777
                                                       777           777
                                                      777           777
                                                     777           777
                                                    777           777
                                                   777           777
                                                  777           777
 
                               444              //   99999999     777777777
                              4444             ///  9999999999   77777777777
                             44 44            ///  999      999           777
                            44  44           ///   99        99          777
                           44   44          ///    999      999         777
                          44    44         ///     99999999999      7777777
                          444444444444    ///         999999999      777
                          444444444444   ///                 99     777
                                44      ///                  99    777
                                44     ///         99        99   777
                              444444  ///           9999999999   777
                              444444  //             99999999   777
                                    © S.Vetter URZ Heidelberg 1986,1994,1997
     SSSSSSSS    KK        KK  RRRRRRRRRR    IIIIIIII  PPPPPPPPP    TTTTTTTT
    SSSSSSSSSS   KK       KK   RRRRRRRRRRR   IIIIIIII  PPPPPPPPPP   TTTTTTTT
   SS        SS  KK      KK    RR        RR     II     PP       PP     TT
   SS            KK     KK     RR        RR     II     PP       PP     TT
    SSS          KK    KK      RR        RR     II     PP       PP     TT
      SSSS       KKKKKKK       RRRRRRRRRRR      II     PPPPPPPPPP      TT
        SSSS     KKKKKKK       RRRRRRRRRR       II     PPPPPPPPP       TT
           SSS   KK    KK      RR    RR         II     PP              TT
             SS  KK     KK     RR     RR        II     PP              TT
   SS        SS  KK      KK    RR      RR       II     PP              TT
    SSSSSSSSSS   KK       KK   RR       RR   IIIIIIII  PP              TT
     SSSSSSSS    KK        KK  RR        RR  IIIIIIII  PP              TT
 
                               ZZZZZZZZZZZZ  UU        UU
                               ZZZZZZZZZZZZ  UU        UU
                                       ZZZ   UU        UU
                                      ZZZ    UU        UU
                                     ZZZ     UU        UU
                                    ZZZ      UU        UU
                                   ZZZ       UU        UU
                                  ZZZ        UU        UU
                                 ZZZ         UU        UU
                                ZZZ          UU        UU
                               ZZZZZZZZZZZZ   UUUUUUUUUU
                               ZZZZZZZZZZZZ    UUUUUUUU
 
   FFFFFFFF   OOOOOOOO   RRRRRRRR  TTTTTTTT RRRRRRRR      AAAAAA    NN     NN
   FFFFFFFF  OOOOOOOOOO  RRRRRRRRR TTTTTTTT RRRRRRRRR    AAAAAAAA   NN     NN
   FF        OO      OO  RR      RR   TT    RR      RR  AA      AA  NNN    NN
   FF        OO      OO  RR      RR   TT    RR      RR  AA      AA  NNNN   NN
   FF        OO      OO  RR      RR   TT    RR      RR  AA      AA  NN NN  NN
   FFFFFFFF  OO      OO  RRRRRRRRR    TT    RRRRRRRRR   AAAAAAAAAA  NN NN  NN
   FFFFFFFF  OO      OO  RRRRRRRR     TT    RRRRRRRR    AAAAAAAAAA  NN  NN NN
   FF        OO      OO  RR  RR       TT    RR  RR      AA      AA  NN  NN NN
   FF        OO      OO  RR   RR      TT    RR   RR     AA      AA  NN   NNNN
   FF        OO      OO  RR    RR     TT    RR    RR    AA      AA  NN    NNN
   FF        OOOOOOOOOO  RR     RR    TT    RR     RR   AA      AA  NN     NN
   FF         OOOOOOOO   RR      RR   TT    RR      RR  AA      AA  NN     NN
 
                                                    777777777     777777777
                                                   77777777777   77777777777
                                                            777           777
                                                           777           777
                                                          777           777
                                                      7777777       7777777
                                                       777           777
                                                      777           777
                                                     777           777
                                                    777           777
                                                   777           777
                                                  777           777
 
                               444              //   99999999     777777777
                              4444             ///  9999999999   77777777777
                             44 44            ///  999      999           777
                            44  44           ///   99        99          777
                           44   44          ///    999      999         777
                          44    44         ///     99999999999      7777777
                          444444444444    ///         999999999      777
                          444444444444   ///                 99     777
                                44      ///                  99    777
                                44     ///         99        99   777
                              444444  ///           9999999999   777
                              444444  //             99999999   777
                                    © S.Vetter URZ Heidelberg 1986,1994,1997
   -  3  -                                                            -  3  -
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                      Vorbemerkungen
                      ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
 
   Dieses Skriptum ist so formatiert, daß es als HTML-File gleichzeitig mit
                       lpr -Pf68umps
   als Postscript-File mit korrektem Seitenumbruch ausgedruckt werden kann,
   z.B. mit Netscape Print... mit Paper Size A4.
 
 
   Besondere Schreibweise innerhalb des Skripts:
 
   DOS-Kommandos, Editor-Kommandos, Debug-Kommandos:
   Ist ein Kommando groß, gegen Ende jedoch kleingeschrieben, so stellt der
   großgeschriebene Teil die Minialabkürzung dar, muß also mindestens soweit
   geschrieben werden. Im übrigen sind unter DOS alle Kommandos unempfindlich
   gegen Groß / Kleinschreibung.
 
   Kursiv geschriebene Angaben müssen durch den entspr. Wert ersetzt werden.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
   -  4  -                                                            -  4  -
 
 
 
 
 
 
 
 
 
                            SKRIPTUM
                          zu Fortran77
 
 
 
                       Inhaltsverzeichnis
                       ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Kapitel 0: Einleitung                                           07
 
   A. WATFOR unter WEDIT (PC)                                      07
      1. Schritt: Workspace bekommt einen Namen (oder Laden File)  07
      2. Schritt: Schreiben / Editieren des Programms              07
      3. Schritt: Ausführen des Programms                          08
      4. Schritt: Ergebnisse / Programmlisting                     08
      5. Schritt: Wie 1. oder 2. oder Editor verlassen             08
      Hilfen für Fortranprogramme am PC                            09
      Ausdrucken eines Files                                       09
      Die Kommandos zum Filehandling (Diskette/Festplatte)         09
 
   B. Wie werden Fortran77-Programme geschrieben?                  10
 
   Kapitel 1: Mensch - Computer - Programm                         11
 
      Was kann der Computer?                                       11
      Warum benutzen wir überhaupt Computer?                       11
      5 Schritte zur Lösung eines Problems mit dem Computer        12
      Erste Beispiele                                              12
      Übungen                                                      14
      Was passiert, wenn man einen Fehler macht?                   14
      Übungen                                                      17
      Programmierstil                                              17
      Zusammenfassung                                              17
      Aufgaben                                                     19
 
   Kapitel 2: Zahlen, Arithmetik und Variablen                     20
 
      Ganze Zahlen (INTEGER)                                       20
      Übungen                                                      20
      Zahlen mit Dezimalpunkt (REAL)                               20
      Konstante, Variable                                          21
      Erklärung des Typs (Deklaration)                             22
      Zuweisung von Werten an Variable                             22
      Einlesen von Werten                                          22
      Umlenken der Standard-Ein/Ausgabe                            24
      Eingebaute Funktionen                                        25
      3 Fehlerquellen bei der Arithmetik mit REAL-Zahlen           25
      Aufgaben                                                     26
 
 
 
 
 
 
 
 
   -  5  -                                                            -  5  -
 
 
 
   Kapitel 3: Entscheidungen und Steueranweisungen                 28
 
      Logische Ausdrücke                                           28
      Der IF-Block                                                 28
      Übungen                                                      31
      Logische Operatoren                                          32
      Aufgaben                                                     32
 
   Kapitel 4: Schleifen                                            34
 
      Schleifen und Schleifensteuerung                             34
      WHILE-Schleife                                               34
      Übungen                                                      34
      DO-Schleife                                                  35
      Übungen                                                      37
      Mehrere Endebedingungen in der Schleife                      37
      Geschachtelte Schleifen                                      38
      Aufgaben                                                     39
 
   Kapitel 5: Felder                                               41
 
      Übungen                                                      42
      Ein- und Ausgabe von Feldern                                 43
      Übungen                                                      43
      2-dimensionale Felder - Tabellen                             43
      Übungen                                                      45
      Höher dimensionierte Felder                                  45
      Angabe einer unteren Indexgrenze                             45
      Zuweisen von Anfangswerten                                   46
      Zusammenfassung                                              46
      Aufgaben                                                     47
      Noch einmal: Schleifensteuerung; der Typ LOGICAL             48
 
   Kapitel 6: Unterprogramme                                       50
 
      Programmeinheiten                                            50
      Subroutine-Unterprogramme                                    50
      Übungen                                                      53
      Function-Unterprogramme                                      54
      Übung                                                        54
      Ein weiteres Beispiel                                        55
      Module, Programmbibliotheken                                 57
      Aufgaben                                                     57
      Dimensionierung zur Ausführungszeit                          59
      Externe Unterprogramme                                       60
      Zusammenfassung: Wirkungsweise des Aufrufs                   61
      Gültigkeitsbereich von Namen                                 62
      Aufgaben (Fortsetzung)                                       62
 
 
 
 
 
 
 
 
 
 
 
 
 
   -  6  -                                                            -  6  -
 
 
   Kapitel 7: Ein- und Ausgabe                                     63
 
      Eingabe                                                      63
      Formen der READ-Anweisung                                    63
      Formatfreie Eingabe                                          64
      Einlesen einer unbekannten Anzahl von Daten                  64
      Formatierte Eingabe: Die Grundgedanken                       66
      Übungen                                                      66
      Ausgabe                                                      67
      Formen der WRITE-Anweisung                                   68
      Formatfreie Ausgabe                                          68
      Formatierte Ausgabe                                          68
      Ausgabe von INTEGER-Zahlen                                   68
      Der I-Code                                                   68
      Der T-Code                                                   69
      Übungen                                                      69
      Der X-Code                                                   69
      Implizite Angabe der Ausgabe-Position                        70
      ASA-Druckersteuerzeichen                                     70
      Übungen                                                      70
      Ausgabe von REAL-Zahlen                                      71
      Der F-Code                                                   71
      Der E-Code                                                   71
      Der D-Code                                                   71
      Der G-Code                                                   72
      Übersicht über alle Formatcodes                              72
      Wiederholungsfaktoren, Code-Gruppen                          74
      Übungen                                                      74
      Aufgaben                                                     75
      Zusammenfassung: Allgemeine Regeln für Formate               75
      Tabellarische Übersicht                                      76
 
   Kapitel 8: Der Typ CHARACTER                                    78
 
      CHARACTER-Werte                                              78
      Konstante, Variable, Ausdrücke                               78
      Eingebaute Funktionen zur Stringverarbeitung                 79
      Übungsbeispiel                                               79
      Aufgaben                                                     81
      Interne Files                                                82
      Ein letztes Beispiel                                         83
 
   Anhang A: Kurzbeschreibung der Syntax von Fortran               87
 
   Anhang B: Literatur zu Fortran                                  89
 
   Anhang C: Der WATFOR Debugger (PC)                              90
 
   Anhang D: Lösungen zu den Übungsaufgaben                        91
          zu Kap. 1                                                91
          zu Kap. 2                                                93
          zu Kap. 3                                                95
          zu Kap. 4                                                98
          zu Kap. 5                                               103
          zu Kap. 6                                               107
          zu Kap. 7                                               113
 
   Index                                                          116
 
 
 
 
   -  7  -                   Kapitel 0: Einleitung                    -  7  -
 
 
                             Kapitel 0: Einleitung
                             ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
 
           A. WATFOR unter WEDIT (PC)
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Falls noch nicht geschehen, schalten Sie Computer und Monitor ein.
   Sonst starten Sie das System ohne Aus- und Einschalten und drücken
           Strg, Alt und Entf gleichzeitig.
   Im Laufwerk darf auf keinen Fall eine Diskette stecken!
 
   Falls Sie mit Diskette arbeiten wollen, legen Sie diese in das entspr.
   Laufwerk. Verwenden Sie die Diskette erstmalig, geben Sie das Kommando
           FORMAT A:     und Return-Taste    für 3 1/4 Zoll Disketten bzw.
           FORMAT B:     und Return-Taste    für 5 1/2 Zoll Disketten
   womit die Diskette "formatiert" ,d.h. zum Beschreiben vorbereitet wird.
   Bei einer beschriebenen Diskette gehen so alle Daten verloren!
 
   Im folgenden wird angenommen, daß Sie mit der Festplatte D: arbeiten;
   mit "Disk" ist die Festplatte (C:,D:..) oder  Diskette(A:,B:) gemeint.
 
   Jetzt starten Sie das WATFOR77-System (automatisch mit Editor WEDIT):
           WATFOR               (und Enter-Taste)
   Damit haben Sie automatisch auf Festplatte (Laufwerk D:) umgeschaltet.
 
   Wollen Sie Ihre Programme und Daten auf Ihre eigene Diskette schreiben,
   schalten Sie um auf Diskettenlaufwerk A: oder B: mit
           SYS A:     bzw.     SYS B:         (und 2 mal die Enter-Taste)
 
   Sie befinden sich jetzt im Workspace mit dem Namen "no_name" (s. 2.
   Zeile) des Editors WEDIT, der in das WATFOR77-System integriert ist.
   Sie haben alle Editor-Kommandos zur Verfügung, wie sie im Skriptum
   zu WEDIT beschrieben sind. Mit dem Betriebssystem MS/DOS haben Sie
   nun nichts mehr zu tun. Wie geht es jetzt weiter?
 
   1. Schritt: Workspace bekommt einen Namen (oder Laden File)
   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Geben Sie Ihrem Programm, welches Sie noch schreiben wollen, einen
   unverwechselbaren Namen anstelle von "no_name" :
           Name neuername             z.B.  Name Prog1
   Er kann bis zu 8 Buchstaben oder Ziffern enthalten. Leerzeichen als
   Teil des Namens sind verboten: z.B. ist   Name P1 2   fehlerhaft!
 
   WATFOR stellt hinter P1 automatisch die Filenamen-Erweiterung .FOR
 
   Beispiel:  N  P1        (das Kommando "Name" ist hier zu "N" abgekürzt)
   gibt dem Workspace den vollständigen Namen "P1.FOR" . Für die meisten
   Kommandos genügt P1 allein ohne ".FOR" (außer für ERAse und REName).
 
   Wenn Sie bereits ein Programm auf Diskette gespeichert haben, geben Sie
   im Schritt 1 das Kommando Edit mit dem Namen des Diskettenprogramms:
           Edit  programmname
   wobei die Erweiterung .FOR wegbleiben kann. Das Kommando Name ist dann
   überflüssig, da Edit dem Workspace den Programmnamen von Diskette gibt.
 
   2. Schritt: Schreiben / Editieren des Programms
   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Schreiben Sie neue Zeilen mit der F5-Taste (Line Insert).
   Eine Zeile kann kopiert werden mit F6 und 2 mal Shift_F6,
   (Line Delete, Line Undelete), d.h. die Zeile wird erst gelöscht (und
   gleichzeitig aufbewahrt), durch Drücken von Shift_F6 sogleich wieder
   eingefügt und steht für weiteres Einfügen an einer bel. Stelle bereit:
   Zeile verschieben: F6, dann F9 / F10  Line Up / Down, dann Shift_F6.
   -  8  -                   Kapitel 0: Einleitung                    -  8  -
 
   3. Schritt: Ausführen des Programms
   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Sie lassen das Programm laufen mit dem Kommando
           RUN                oder Alt_F1   (Alt und F1 gleichzeitig)
   Sie erhalten alle Meldungen von WATFOR77 am Schirm gelistet; falls
   kein Error dabei war, wird das Programm automatisch ausgeführt und
   Sie erhalten die Ergebnisse ebenfalls am Schirm.
 
   Falls Sie die Anweisung READ* verwenden, wird die Eingabe der Daten
   interaktiv am Schirm erwartet (es gibt aber auch die Möglichkeit,
   die Daten in einem File auf Disk zu halten, s.u.).
   Wenn Sie die Ergebnisse nicht am Schirm haben wollen, sondern auf
   Diskette (zusammen mit dem Programmlisting), geben Sie das Kommando
           RUN/NOXType        oder Alt_F3   (Alt und F3 gleichzeitig)
 
   Wollen Sie die gesamte Bildschirm- Ein- und Ausgabe (PRINT und READ)
   außer am Schirm auch noch im Listing, geben Sie
           RUN/LOgio          oder Alt_F5   (Alt und F5 gleichzeitig)
 
   Die Ausführung des Programms bzw. der Compilation kann mit den Tasten
           Strg_Untbr         (Strg und Untbr gleichzeitig)
   angehalten werden. Dies ist besonders für Endlosschleifen (s.u.) ge-
   dacht. Auf die Frage "Do you really want to stop" antworten Sie "y".
   Wollen Sie nach einem READ* (der Aufforderung zur Eingabe am Schirm,
   s.u.) das Programm abbrechen: Strg_Untbr und dann Enter drücken.
 
   4. Schritt: Ergebnisse / Programmlisting
   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Mit dem Kommando RUN wird automatisch ein File auf Diskette angelegt
   mit dem Namen des Programms, jedoch Kennzeichnung .LST (statt .FOR).
   z.B. erzeugt das Programm P1 (also P1.FOR) das Listing-File P1.LST
   Wollen Sie sich das Listing ansehen, so geben Sie das Kommando
           Edit programmname.LST              (also z.B.  E P1.LST)
   womit der Editor einen 2. Workspace anlegt. Die Rückkehr in den 1.
   Workspace zum Verbessern / Erweitern Ihres Fortranprogramms geht mit
           Edit       oder  Shift_F7
   womit der 2. Workspace verlassen wird. Dieser bleibt jedoch für ein
   weiteres Edit erhalten, sodaß Sie mit E (oder Shift_F7) zwischen
   Listing und Quellprogramm hin und her schalten können. Doch werden
   i.a. Änderungen des Listings kein lauffähiges Programm ergeben!
 
   Bevor Sie die neue Version Ihres Quellprogramms mit RUN laufen lassen,
   geben Sie im Workspace des (ungeänderten) Listings das Kommando
           QUIT       oder  Strg_F6
   womit das Listing gelöscht wird und Sie später mit Edit P1.LST das
   neue Listing bekommen (sonst geht Edit P1.LST wieder in das alte!).
 
   5. Schritt: Wie 1. oder 2. oder Editor verlassen
   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Weiter mit Schritt 2 (Bearbeitung desselben Programms) oder mit
   Schritt 1 (Bearbeitung eines anderen Programms): dabei wird mit
           Put        oder  Put neuername
   eine dauerhafte Kopie mit altem (Put allein) oder neuem Namen erstellt.
 
   Am Ende Ihrer Arbeit verlassen Sie den Editor mit
           EXit
   Dabei wird automatisch die aktuelle Version Ihres Workspaces (das
   Programm) auf Disk gesichert (mit dem vollen Namen). Wollen Sie das
   nicht, verlassen Sie den laufenden Workspace unwiderruflich mit
           QUIT
   Alle vorhandenen Workspaces werden unwiderruflich gelöscht mit
           CANcel
   Erst nach EXit / QUIT nehmen Sie Ihre Diskette aus dem Laufwerk.
   -  9  -                   Kapitel 0: Einleitung                    -  9  -
 
 
           Hilfen für Fortranprogramme am PC
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   1. Voreinstellung Tabulator-Taste:
   springt von Sp. 1 auf Sp. 7, sodann in Zweierschritten zum bequemen
   Einrücken von Blöcken (WHILE, IF usw.); mit Shift auch rückwärts.
 
   2. Automatischer Piepston in Spalte 72
   Spalte 72 ist durch einen Piepston markiert; schreiben Sie statt in
   Sp. 73 in der nächsten Zeile ab Sp. 7 weiter (also F5 und Tabulator);
   vergessen Sie dabei nicht, etwas (ungleich 0) in Sp. 6 einzutragen!
 
   3. Großbuchstaben ohne Shift-Taste:
   Der Fortran77-Standard fordert, daß alle Anweisungen in Großbuchstaben
   geschrieben sind. WATFOR erlaubt auch Kleinbuchstaben (entsprechend dem
   Fortran90-Standard), die von Fortran jedoch nicht von Großbuchstaben
   unterschieden werden; sie dienen nur der besseren Lesbarkeit.
   Das Schreiben von Großbuchstaben erleichtern Sie sich durch einmaliges
   Drücken der Taste "Groß" (wird durch ein grünes Licht rechts oben
   angezeigt); das Drücken der Shift-Taste bei Buchstaben entfällt damit;
   alle Ziffern und Sonderzeichen schreiben sich aber weiterhin wie gewohnt.
 
   Programmierte Tasten mit Alt:
 
   4. Kommando RUN/NOEXtensions auf Alt_F1
   Das Kommando startet ein Fortran-Programm und unterdrückt Extension-
   Meldungen. Besonderheit: Man kann Alt_F1 auch mitten aus der Text-Area
   heraus drücken (man muß den Cursor nicht mit F4 nach unten bewegen).
 
   5. Kommando RUN/NOEX/NOXType auf Alt_F3
   Wie oben, jedoch werden die Ergebnisse (PRINT*,...) ins Listing-File
   geschrieben, dh. es ist kein Bildschirm-Dialog möglich.
 
   6. Kommando RUN/NOEX/LOgio auf Alt_F5
   Die gesamte Bildschirm- Ein- und Ausgabe ist am Schirm sichtbar und
   wird zusätzlich im Listing-File vermerkt.
 
           Ausdrucken eines Files
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Drucken eines Files über die Netzwerk-Drucker: Sie drücken
            Alt_F2           (Alt und F2 gleichzeitig)
   und tippen den Namen des zu druckenden Files, dann die Enter-Taste.
 
           Die Kommandos zum Filehandling (Diskette/Festplatte)
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
     DIrectory            zeigt das Inhaltsverzeichnis der Disk
     Get abc              kopiert File abc hinter die Current Line
     Put abc              schreibt den lfd. Workspace in das File abc
     Name   abc           gibt dem Workspace den neuen Namen abc
     SHow                 zeigt die Namen aller Workspaces (Strg_F5)
     Edit   abc           erzeugt einen 2. (allg. weiteren) Workspace abc
     Edit                 geht in den 2. (allg. nächsten)  Workspace
     DONe                 geht in den 2. (allg. nächsten)  Workspace und
                          schreibt auf Disk zurück, falls Änderung;
     BYE                  geht in den 2. (allg. nächsten)  Workspace und
                          löscht lfd. Workspace, falls keine Änderung
     QUIT                 geht in den 2. (allg. nächsten)  Workspace und
                          löscht den laufenden Workspace
     EXIT                 verläßt Workspace mit Zurückschreiben auf Disk
     CANcel               verläßt unwiderruflich den Editor
     ERAse  abc           löscht das File abc von der Disk
     REName abc xyz       gibt dem File abc den neuen Namen xyz
 
   -  10 -                   Kapitel 0: Einleitung                    -  10 -
 
 
          C. Wie werden Fortran-Programme geschrieben?
          ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   In Fortran gibt es eine feste Spalteneinteilung:
 
   Zeilenlineal:
 
   ....;....1....;....2....;....3....;....4....;....5....;....6....;....7..
 
   Einteilung einer Fortran-Zeile:
 
   nnnnnfaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
 
   Dabei bedeutet:
 
     n : Nummernfeld: 1-5 Ziffern
             für Formatnummern und Anweisungsnummern
 
     f : Fortsetzungsspalte:
             mit bel. Zeichen ungleich 0 gehört die Zeile zur vorigen
             Vorschlag: man verwende &
 
     a : Anweisungsfeld:
             für Fortran-Anweisungen
 
   zweite Möglichkeit für eine Fortran-Zeile:
 
   *.......................................................................
 
   Dabei bedeutet:
 
     * : * in Sp. 1 (anstelle von * kann auch C stehen)
     . : beliebiger Kommentar
 
   Der Inhalt ab Spalte 73 bis Zeilenende einer Fortran-Programmzeile
   wird ignoriert (kann für Kommentar verwendet werden).
 
   Eine Fortran-Anweisung beginnt immer auf einer neuen Zeile.
 
   Falls eine Zeile nicht reicht, kann die Anweisung mit dem Eintrag in
   die Fortsetzungsspalte der nächsten Zeile fortgesetzt werden (bis zu
   19 mal). Die Spalten 7-72 der Fortsetzungszeile(n) verhalten sich so,
   als ob sie ab Spalte 73 der Anweisung angefügt wären.
 
   Leerzeichen (blanks) können zur besseren Lesbarkeit beliebig in einer
   Anweisung verwendet werden. Sie haben für Fortran keine Bedeutung,
   es sei denn, sie treten innerhalb eines CHARACTER-Strings in
   Hochkomma auf, z.B. ' ' oder 'Otto Meier' als Bestandteil des Textes.
 
   Vermeiden Sie Leerzeichen innerhalb von Namen und Schlüsselwörtern!
     Beispiel: INTEGER, niemals INT EGER schreiben.
 
   Innerhalb von Namen kann mit _ gegliedert werden:
 
     Beispiel: Guthaben_alt, Guthaben_neu
 
 
 
 
 
 
 
 
   -  11 -          Kapitel 1: Mensch - Computer - Programm           -  11 -
 
 
                    Kapitel 1: Mensch - Computer - Programm
                    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
           Fragen
 
     1. Was kann eigentlich genaugenommen ein Computer?
     2. Wenn das alles ist, warum verwenden wir Computer überhaupt?
     3. Welche Schritte sind nötig, um ein Problem zu lösen?
     4. Was passiert, wenn man einen Fehler macht?
 
           Was kann der Computer?
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Wie viele elektronische Bestandteile ein Computer auch haben mag, sie
   haben alle im wesentlichen die folgenden 3 grundlegenden Eigenschaften:
     1. Jeder Computer hat Schaltkreise für arithmetische Operationen,
        meist + - * /  (Addition, Subtraktion, Multiplikation, Division).
     2. Jeder Computer hat Schaltkreise, um Entscheidungen zu treffen.
        Die Entscheidungen sind nicht von der Art: "Wer würde den Krieg
        gewinnen zwischen Vietnam und den USA?", sondern der Computer
        kann nur entscheiden, ob eine Zahl kleiner, gleich oder größer
        ist als eine andere Zahl.
     3. Jeder Computer hat die Möglichkeit, mit dem Menschen zu kommuni-
        zieren, sonst hätte alle Rechnerei ja keinen Sinn. Die Eingabe von
        Information geschieht heute meist über Tastatur / Bildschirm.
        Zur Ausgabe der Information aus dem Computer wird entweder ein
        Drucker oder ebenfalls der Bildschirm verwendet.
 
   Da alle Computer nur diese 3 Arten von Fähigkeiten haben - einfache
   Arithmetik, einfache Entscheidungen, Ein- und Ausgabe - , stellt sich
   die Frage:
 
           Warum benutzen wir überhaupt Computer?
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Es gibt darauf im wesentlichen 3 Antworten:
 
   1. Schnelligkeit.
      Ein heutiger Rechner kann etwa 100 Millionen Additionen pro Sekunde
      ausführen. Ein Mensch braucht dazu 125 Jahre, wenn er 40 Stunden
      die Woche arbeitet. Entscheidungen laufen ebenso schnell ab.
      Das Drucken erfolgt z.T. mechanisch und ist daher wesentlich langsamer,
      ein Laser-Schnelldrucker am URZ druckt 4000 Zeilen pro Minute.
   2. Genauigkeit und Verläßlichkeit.
      Die Berechnungen der Computer sind meist (Ausnahmen s. später)
      sehr genau und jederzeit reproduzierbar; hin und wieder bricht ein
      Computer auch zusammen, meistens wegen falscher Bedienung
      oder fehlerhafter Programmierung, seltener wegen Hardware-Fehlern;
      meist kann er schnell wieder zum Laufen gebracht werden.
   3. Ein großes Problem = eine Menge kleiner Probleme
      Der wichtigste Grund, der für Computer spricht, ist die Möglichkeit,
      große Probleme mit dem Computer dadurch zu lösen, daß man eine große
      Zahl kleiner Probleme daraus macht und diese eins nach dem anderen
      - der Reihe nach - löst; z.B. ist die Erzeugung einer Aufstellung
      aller Lohnzahlungen in einer großen Firma ein großes Problem.
      Wir müssen dazu folgendes tun:
      a) Eingabe von: Lohn, Steuer, Pensions-Ansprüche, geleistete
         Arbeitsstunden usw. für jeden Beschäftigtrn.
      b) Ausführung einiger einfacher arithmetischer Operationen.
      c) Ausgabe einiger Zeilen als Ergebnis der Berechnungen.
      Durch einfaches Wiederholen für jeden einzelnen Fall können wir
      die Aufgabe lösen.
 
 
 
   -  12 -          Kapitel 1: Mensch - Computer - Programm           -  12 -
 
 
           5 Schritte zur Lösung eines Problems mit dem Computer
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   1. Beschreibe das Problem
      Ehe ein Problem nicht genau (auf Deutsch) beschrieben ist, hat es
      wenig Sinn, mit dem Computer zu arbeiten. In der Datenverarbeitung
      bekommen diejenigen die höchsten Löhne, die die Frage beantworten:
      "Was, genau, ist es, wozu wir den Computer einsetzen wollen?".
   2. Entwickle einen Algorithmus
      Ein Algorithmus ist eine Folge von Anweisungen, wie der Weg zur
      Lösung des Problems aussehen soll. Es gibt verschiedenen Formen
      der Darstellung von Algorithmen. Eine dieser Formen wird unten an
      Beispielen ausführlich dargestellt. Wenn der Algorithmus einmal
      formuliert ist, ist die Programmierung bedeutend einfacher.
   3. Übersetze den Algorithmus in eine Programmiersprache (Fortran).
      Die Anweisungen in der neuen Sprache nennt man Computerprogramm.
      Es gibt Hunderte solcher Sprachen, genaugenommen versteht aber der
      Computer nur  e i n e  Sprache, und diese besteht nur aus Nullen
      und Einsen ("Maschinensprache"). Das Programm, welches Fortran-
      Anweisungen in Maschinensprache übersetzt, nennt man Compiler:
      es ist selbst in Maschinensprache geschrieben.
   4. Schreibe das Programm am Bildschirm
      Nachdem das Programm in Fortran geschrieben ist, gibt man es am
      Schirm in den Computer ein. Das eingetippte Fortran-Programm nennt
      man  Quellprogramm.
   5. Lasse das Programm laufen (Compilation, sodann Ausführung)
      Das Laufenlassen ist ein Prozeß mit 2 Schritten:
      a) Das Fortran-Quellprogramm wird vom Compiler in Maschinensprache
         übersetzt. Gleichzeitig zeigt der Compiler das eingegebene
         Programm an, zusammen mit Meldungen über die Compilation und
         über eventuelle Fehler (Verstöße gegen die Fortran-Regeln).
         Man sagt, diese Vorgänge laufen zur "compile time" ab.
      b) Der 2. Schritt besteht darin, daß der Computer die Anweisungen
         ausführt, die im Programm enthalten sind. Dies geschieht zur
         "execution time". Alle Fehler, wie Division durch 0, beenden die
         Ausführung des Programms, und eine Fehlermeldung wird ausgegeben.
         Schematisch sieht das so aus:
 
    Compile time:
    Quellprogramm   --->   WATFOR77 Compiler  --->  Listing des Programms
                                   |                  mit Fehlermeldungen
    Execution time:                |
    (nur falls kein                v
    compile time error)    Maschinenprogramm  --->  Ergebnisse
                                                      mit Fehlermeldungen
 
   Beispiel 1.1
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Aufgabenstellung: Die Botschaft "Mein erstes Fortran-Programm" soll
                     auf dem Bildschirm erscheinen.
         PROGRAM P11
   * Beispiel 1.1: Zeige am Schirm: "Mein erstes Fortran-Programm"
         PRINT*, 'Mein erstes Fortran-Programm'
         END
 
   Erklärungen:
   1. Die 1. Zeile ist der Programm-Kopf. Hier wird der Name des Programms
      angegeben, hier: P11
   2. Die 2. Zeile ist Kommentar. Kommentar beginnt mit * in Sp. 1 und
      umfaßt die ganze Zeile.
      Kommentare haben auf die Logik des Programms keinen Einfluß.
   3. Die übrigen Zeilen enthalten die Anweisungen, die der Computer
      ausführen soll, eine PRINT-Anweisung und die END-Anweisung.
   -  13 -          Kapitel 1: Mensch - Computer - Programm           -  13 -
 
   Beispiel 1.2
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Aufgabenstellung: Es soll der Zinsertrag berechnet werden für 100 DM
                     in 1 Jahr bei einem Zinssatz von 12 %.
         PROGRAM P12
   * Beispiel 1.2: Zinsertrag für 100 DM in 1 Jahr bei 12%
         REAL Kapital, Zinsertrag
         Kapital    = 100
         Zinsertrag = Kapital * 0.12
         PRINT*,'Kapital:',Kapital,' Zinsertrag bei 12% Zins:',Zinsertrag
         END
 
   Erklärungen:
   1. Kapital und Zinsertrag sind Variable vom Typ REAL.
      Variable können die Ergebnisse von Berechnungen des Computers
      enthalten. Alle Variablen werden am Anfang mit ihrem Typ deklariert
      (s.a. Kap. 2). Der Typ REAL steht für Zahlen mit Dezimalpunkt.
   2. Jede Anweisungen beginnt auf einer neuen Zeile. Sie kann auch
      über mehrere Zeilen gehen, z.B. hätten wir schreiben können:
         PRINT*,  'Kapital:',Kapital,
        &         ' Zinsertrag bei 12% Zins:',Zinsertrag
      mit einem & in Sp. 6 der Fortsetzungszeile.
   3. Die Anweisung   "Kapital = 100"
      bedeutet: es wird der Wert 100 genommen und dem Kapital zugewiesen
         Zinsertrag = Kapital * 0.12
      bedeutet: es wird der Wert von Kapital mit 0.12 multipliziert; der
      so errechnete Wert wird der Variablen Zinsertrag zugewiesen.
         Variable = ...    heißt also:
      der Variablen wird der (berechnete) Wert zugewiesen
 
   Wenn Sie das Programm mit  RUN starten, erhalten Sie die Meldung
      *EXT* CC-04 line 3, character encountered is not FORTRAN77 standard
   Diese Meldung können Sie ignorieren (sie wird durch die Kleinbuchstaben
   von "Kapital" und "Zins" verursacht). Starten Sie statt mit "RUN" mit
      "RUN/NOEX"     oder besser mit Alt_F1 (programmierte Taste, s.o.
   Kap. 0), und die Meldung wird unterdrückt.
 
   Beispiel 1.3
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Aufgabenstellung: Wie 1.2, aber Zinsertrag für 10 Jahre berechnen
         PROGRAM P13
   * Beispiel 1.3: Wie 1.2, aber Zinsertrag für 10 Jahre berechnen
         REAL Kapital, Zinsertrag
         INTEGER Jahr
         Kapital = 100
         Jahr    = 1991
         WHILE (Jahr .LE. 2000)
            Zinsertrag = Kapital * 0.12
            PRINT*,      Kapital,Zinsertrag
            Kapital    = Kapital + Zinsertrag
            Jahr       = Jahr + 1
         ENDWHILE
         END
 
   Erklärungen:
   1. Die WHILE-Anweisung führt den Block der Anweisungen bis ENDWHILE
      solange aus, wie Jahr kleiner oder gleich 2000 ist: "Jahr .LE. 2000"
      Dabei steht .LE. für "Lower or Equal" (kleiner oder gleich).
      Eine Wiederholung von Anweisungen nennt man eine Schleife.
      Innerhalb der Schleife WHILE ... ENDWHILE wird das Jahr um 1 erhöht,
      sodaß nach 10 Schritten 2000 erreicht ist. Beim 11. Mal ist die
      Bedingung, daß das Jahr kleiner oder gleich 2000 ist, nicht mehr
      erfüllt; das Innere der Schleife wird nicht mehr ausgeführt.
   -  14 -          Kapitel 1: Mensch - Computer - Programm           -  14 -
 
   2. Es gibt 6 Vergleichsmöglichkeiten (Vergleichs-Operatoren):
        .LT.  kleiner  .GT.  größer               .NE.  ungleich
        .EQ.  gleich   .LE.  kleiner oder gleich  .GE.  größer oder gleich
   3. Die Anweisung "Jahr = Jahr + 1" bedeutet: Es wird der Wert von
      Jahr + 1 berechnet und das Ergebnis der Variablen Jahr zugewiesen.
 
      Übungen
      ¯¯¯¯¯¯¯
   1. Ändern Sie Beispiel 1.3 für einen Zinssatz von 9 %.
   2. Ändern Sie Beispiel 1.3 für 1000 DM und 5 Jahre.
   3. Ändern Sie Beispiel 1.3, sodaß Jahr, Kapital, Jahresertrag und
      der gesamte Zinsertrag angezeigt werden.
 
            Was passiert, wenn man einen Fehler macht?
            ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Wenn eine Fortran-Anweisung Fehler enthält ( Syntax-Fehler), wird nach
   dem RUN die entspr. Fehlermeldung angezeigt mit Angabe der Zeile, wo
   der Fehler auftrat ("line ..."). Drücken Sie Enter und tippen Sie die
   Zeilennummer (n) als Kommando ein:
   Tippen Sie  :n  und Enter):
           die fehlerhafte Zeile erscheint hell (Current Line).
   Im folgenden werden einige häufig auftretende Fehler und deren Behebung
   besprochen. Zunächst einige Syntax-Fehler (compile time error):
 
   Beispiel 1.4
   ¯¯¯¯¯¯¯¯¯¯¯¯
          PROGRAM P14
   * Beispiel 1.4: 5 verschiedene Syntax-Fehler
          REAL x,y,z
          x = 2,0
          y = x*x - 3x
          z = (x+y)/y+2,0)
          PRINT*x,y,z
          END
 
   Nach dem Programmstart (Alt_F1) erscheinen folgende Syntax-Fehler:
 
     *ERR* SX-02 line 4, at end of statement, bad sequence of operators
     *ERR* SX-16 line 5, column 18, missing operator
     *ERR* PC-04 line 6, column 23, unmatched parentheses
     *ERR* SX-10 line 7, column 12, missing comma
 
   Geben Sie das Kommando "4" für line 4 usw.
 
   line 4: hier ist nicht sofort zu entnehmen, daß anstelle des Kommas
           in einer Dezimalzahl der Dezimalpunkt stehen muß.
   Korrektur: schreiben Sie statt , einen .
 
   line 5: hier ist eine Spalte (column 18) angegeben: drücken Sie F4
           und bewegen Sie den Cursor auf Spalte 18 (sichtbar in der 2.
           Zeile rechts oben, wo hinter der 4 (=Zeile 4) die Spalte steht)
   Korrektur: 3 mal X schreibt man in Fortran "3*X".
 
   line 6: hier fehlt eine Klammer; die Spaltenangabe ist irreführend,
           da der Compiler das Unglück erst am Zeilenende merkt!
   Korrektur: die Klammer-auf hinter / fehlt.
 
   line 7: hier fehlt das Komma hinter dem *
   Korrektur: fügen Sie hinter dem * ein , ein
 
   Haben Sie alles verbessert und drücken wieder Alt_F1, so tritt ein
   neuer, bisher unbemerkter Fehler auf:
     *ERR* SX-16 line 6, column 23, missing operator
   -  15 -          Kapitel 1: Mensch - Computer - Programm           -  15 -
 
   Der Fehler ist wieder, daß ein , statt . (Dezimalpunkt) dasteht.
   Wir lernen daraus: Obwohl beidesmal derselbe Fehler gemacht wurde,
   nämlich eine REAL-Zahl 2,0 zu schreiben statt 2.0, meldet der Compiler
   verschiedene Fehler mit unterschiedlicher "Erklärung": oben war es
   SX-02 "bad sequence of operators" und jetzt SX-16 "missing operator".
 
   Execution-Time-Fehler (z.B. Division durch 0) geben die Nummer der
   Fortran-Anweisung an ("statement ..."). Die Nummer zeigt aber nur dann
   auf die fehlerhafte Zeile, wenn weder Kommentar noch Fortsetzungszeilen
   vorhanden sind (was meist nicht so ist). Zählen Sie also nur die
   Fortran-Anweisungen, oder noch besser, editieren Sie das Listing-File
   und schauen Sie nach, welche Zeile das "statement ..." war
   (im Listing-File in Sp. 7 links vor jeder Fortran-Zeile angegeben).
   Zur Erinnerung: zum Programm z.B. P14.FOR gehört das Listing P14.LST
 
   Beispiel 1.5
   ¯¯¯¯¯¯¯¯¯¯¯¯
          PROGRAM P15
   * Beispiel 1.5: Division durch 0
   * identisch mit dem (inzwischen hoffentlich) verbesserten Beispiel 1.4
          REAL x,y,z
          x = 2.0
          y = x*x-3*x
          z = (x+y)/(y+2.0)
          PRINT*,x,y,z
          END
 
   Resultat:
   *ERR* KO-01 floating point divide by zero
   TraceBack: Executing in P15, statement 5
   Erklärung:
   Der Fehler, eine Division durch 0, tritt auf, weil Y den Wert -2 in
   Zeile 6 bekommt und in Zeile 7 durch Y+2.0 also durch 0 dividiert wird.
   Das Traceback nennt "statement 5". Dies muß nicht die 5. Zeile sein.
   Im Beispiel ist es Zeile 7. Sehen Sie im Listing nach statement 5. Dort
   sind die Anweisungen (statements) links vorn durchlaufend numeriert.
 
   Beispiel 1.6
   ¯¯¯¯¯¯¯¯¯¯¯¯
          PROGRAM P16
   * Beispiel 1.6: Rechnen mit undefiniertem Wert
          REAL a,b
          b = a*a
          a = 7.0
          PRINT*,b
          END
 
   Resultat:
   *ERR* UV-05 the value of A is undefined
   TraceBack: Executing in P16, statement 3
   Erklärung:
   Der Fehler besteht darin, daß bei Ausführung der Anweisung "B = A*A"
   die Variable A noch keinen Wert besitzt (dies wird erst in der nächsten
   Anweisung "nachgeholt").
 
   Beispiel 1.7
   ¯¯¯¯¯¯¯¯¯¯¯¯
          PROGRAM P17
   * Beispiel 1.7: Ausgabe eines undefinierten Wertes
          REAL b
          PRINT*,b
          END
   Resultat:       ????????
   -  16 -          Kapitel 1: Mensch - Computer - Programm           -  16 -
 
   Erklärung: Bei der Ausführung der PRINT-Anweisung hatte B noch keinen
   Wert. Die Ausgabe eines undefinierten Wertes gilt aber nicht als
   Fehler, sondern wird mit ???????? angezeigt.
 
   Beispiel 1.8
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Aufgabenstellung: Berechnung der Summe der ersten 50 natürlichen Zahlen
                     und deren Durchschnittswert
         PROGRAM P18
   * Beispiel 1.8: Summe der ersten 50 natürlichen Zahlen mit Durchschnitt
         INTEGER Summe, Zahl, Durchschnitt
         Summe = 0
         Zahl  = 1
         WHILE( Zahl .LE. 50 )
            Summe = Summe + Zahl
            Zahl  = Zahl + 1
         ENDWHILE
         Durchschnitt = Summe / 50.0
         PRINT*, 'Durchschnitt =', Durchschnitt
         END
 
   Beispiel 1.9
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Schritt 1: Idee zur iterativen Berechnung der Quadratwurzel:
      Ausgangspunkt: Gegeben sei die Zahl A.
 
        1. Näherung: X = A/2
                      ¹
                            1
          2. Näherung: X  = - ( X  + A/X  )
                        ²   2    ¹      ¹
                               1
            3. Näherung:  X  = - ( X  + A/X  )    usw.
                           ³   2    ²      ²
   Schritt 2: Algorithmus:
 
      1) setze  Zahl          = 726.4
      2) setze  alte Näherung = Zahl  (der Wert wird unten in 5) benutzt;
                                      ansonsten ist er beliebig; darf aber
                                      nicht gleich Zahl/2 sein. Warum? )
      3) setze  Näherung      = Zahl/2
      4) setze  Zähler        = 1
      5) WHILE Differenz alte und neue Näherung größer als 0.001
         5.1) erhöhe Zähler um 1
         5.2) setze  alte Näherung = Näherung
         5.3) setze  Näherung = ... s.o. Formel
      6) Schreibe den Wert der Zahl, der Näherung und des Zählers
 
   Schritt 3: Übersetzung in Fortran:
         PROGRAM P19
   * Beispiel 1.9: Iterative Berechnung der Wurzel aus 726.4
   *          Stop, wenn die letzte Verbesserung kleiner als 0.001 ist
         REAL Zahl, alte_Naeherung, Naeherung
         INTEGER Zaehler
         Zahl           = 726.4
         alte_Naeherung = Zahl
         Naeherung      = Zahl / 2.0
         Zaehler        = 1
         WHILE( ABS (alte_Naeherung - Naeherung) .GT. 0.001)
           alte_Naeherung = Naeherung
           Naeherung      = ( alte_Naeherung + Zahl/alte_Naeherung ) / 2.0
           Zaehler =      Zaehler + 1
         ENDWHILE
   -  17 -          Kapitel 1: Mensch - Computer - Programm           -  17 -
 
         PRINT*,'Wurzel aus',Zahl,' nach',Zaehler-1,' Iterationen ist',
        &      Naeherung)
         END
 
   Anm.: Die Fortran-Funktion ABS berechnet den Absolutbetrag, s.u. Kap. 2
 
      Übungen
      ¯¯¯¯¯¯¯
   Modifizieren Sie das Beispiel 1.9 so, daß
   1. a) jede Näherung ausgegeben wird
      b) Stop nach 6 Iterationen
      c) Stop, wenn die Änderung der Näherung kleiner als 0.1 % des
         Wertes der Zahl ist. Ist das ein guter Gedanke?
   2. Mit der Fortran-Funktion SQRT kann der (hoffentlich!) genaue
      Wert der Quadratwurzel bestimmt werden. Man modifiziere das
      Programm so, daß Wurzel aus 7 auf 0.001 genau berechnet wird
      und vergleiche mit dem Wert von SQRT(Zahl).
   3. Was passiert, wenn das Programm die Wurzel aus einer negativen
      Zahl berechnen soll? (ausprobieren!) Was wäre zu tun, um auch
      diesen Fall vom Programm richtig zu verarbeiten?
 
            Programmierstil
            ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Gut geschriebene Programme haben folgende Eigenschaften:
   1. Viele Kommentare
   2. Leerzeichen trennen einzelne Symbole, Operatoren und Programmteile
   3. Namen der Variablen nach ihre Bedeutung
   4. Anweisungen einrücken zwischen WHILE und ENDWHILE
 
            Zusammenfassung
            ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   A. Stichworte:
 
      Bit, Byte
      Hardware, Software
      Maschinensprache, Hochsprache, Fortran
      Fortran-Programm, Anweisung, Zuweisung, Kommentar
      Compiler, Compilation, Compile Time
      Execution, Execution Time
      Extension, Warning, Error
      Syntax-Fehler, Compile Time Error
      Fehler bei der Ausführung, Execution Time Error
      Character, Zeichen, Zahl, Ziffer, Buchstabe
      ganze Zahl, gebrochene Zahl, Dezimalzahl, Dezimalpunkt
      Algorithmus, iterativer Algorithmus
 
   Machen Sie sich für diese Stichworte deren Bedeutung und den
   Zusammenhang klar. Fragen Sie, wenn Ihnen etwas unklar ist.
 
   B. 5 Schritte der Programmentwicklung:
 
   1. Definieren Sie das Problem.
   2. Entwickeln Sie einen Algorithmus zur Lösung des Problems.
   3. Übersetzen Sie diesen in eine Computersprache (Fortran).
   4. Geben Sie die Anweisungen in den Computer (am Bildschirm).
   5. Lassen Sie den Computer die Anweisungen ausführen.
 
   C. Fortran-Typen
 
   Fortran verarbeitet 3 Arten von Zahlen:
      ganze Zahlen:      Typ INTEGER
      gebrochene Zahlen: Typ REAL
      komplexe Zahlen:   Typ COMPLEX , wird im Skript nur am Rande erwähnt
   -  18 -          Kapitel 1: Mensch - Computer - Programm           -  18 -
 
   Weiter gibt es noch in Fortran:
      logische Werte    .TRUE. und .FALSE. als wahr / falsch) s. Kap. 3
                        der Typ LOGICAL wird am Ende von Kap. 5 behandelt
      bel. Zeichen      Text in Hochkomma: '...'
                        der Typ CHARACTER wird in Kap. 8 behandelt.
 
   D. Fortran-Programme haben die Form
 
         PROGRAM name
         Deklarations-Teil (Angabe von Typ und entspr. Variablen)
         Anweisungs-Teil (executable statements)
         END
 
         Kommentar (* in Sp. 1) kann an beliebiger Stelle stehen.
 
   E. In den Beispielen wurden folgende Anweisungen benutzt:
     1. PROGRAM ... gibt dem Programm einen Fortran-Namen
     2. Kommentarzeilen mit * in Spalte 1
     3. INTEGER ... | REAL ...  vereinbaren Variable als INTEGER | REAL
     4. Die Zuweisung       ... = ... weist der links stehenden Variablen
        einen Wert zu: Variable = Wert
     5. Die WHILE-Anweisung steuert, wie oft eine Schleife, d.h. die
        Anweisungen bis ENDWHILE, ausgeführt werden.
     6. Die PRINT-Anweisung zeigt Texte und Ergebnisse am Schirm.
     7. Die eingebauten Funktionen ABS für den Absolutbetrag und SQRT
        für die Quadratwurzel.
     8. END  ist die letzte Zeile des Programms, beendet den Programmlauf.
 
   F. Fehlermeldungen.
   Der Compiler unterscheidet 3 Stufen von Meldungen:
   1. Extension
      Erweiterung (Vorgriff auf den Fortran90-Standard).
      Das Anzeigen dieser Meldungen kann durch die Verwendung der
      programmierten Taste Alt_F1 (statt des Kommandos RUN) unterdrückt
      werden (wirkt wie RUN/NOEX).
   2. Warning
      Stellt keinen eigentlichen Fehler dar, sollte jedoch ernst genommen
      werden (z.B. der Hinweis auf Anweisungen, die niemals ausgeführt
      werden können u.ä.).
   3. Error
      a) Syntax-Fehler: Fehler, die zur sog. "compile time" auftreten.
         Diese Fehler werden bis Programmende gesammelt; falls vorhanden,
         wird das Programm nicht zur Ausführung gebracht.
      b) Fehler während der Ausführung (execution time error).
         Beim ersten Auftreten wird der Programmlauf gestoppt.
         Mit Hilfe des Debuggers kann man an dieser Stelle nach einer
         lokalen Korrektur evtl. den Programmlauf fortsetzen.
 
   Die Korrektur von Fortran-Syntax-Fehlern ist im Prinzip einfach, doch
   muß man beachten, daß der Compiler für denselben Schreibfehler in
   verschiedenen Zeilen u.U. verschiedene Fehlermeldungen erzeugt, s.o.
   Beispiel 1.4; umgekehrt kann es sein, daß für einen einzigen Fehler
   mehrere Fehlermeldungen ausgegeben werden, von denen vielleicht nur eine
   den Fehler zutreffend beschreibt. Beheben Sie also die Fehler unbedingt
   der Reihe nach; im Zweifel nur einen Fehler auf ein Mal (sodann RUN);
   der Compiler ist so schnell, daß Sie dadurch kaum Zeit verlieren!
   Execution time error sind meist sehr gefürchtet, da viele
   Fortran-Compiler einen im Stich lassen mit sinnvollen Meldungen
   und allenfalls kryptische Systemmeldungen erzeugen, womit man nur
   wenig anfangen kann. Anders der WATFOR-Compiler: Er besitzt eine
   ausgezeichnete Execution Time Fehlerdiagnostik.
   Kommt trotz allem das gewünschte Ergebnis nicht heraus, kann evtl.
   noch der Debugger helfen, s. Anhang C.
   -  19 -          Kapitel 1: Mensch - Computer - Programm           -  19 -
 
           Aufgaben
           ¯¯¯¯¯¯¯¯
   1. Berechnen Sie die Summe von 127 und 584
 
   2. Schreiben Sie Ihren Namen in großen Buchstaben wie unten;
      benutzen Sie eine Folge von PRINT-Anweisungen.
 
          *****  *   *  *   *   ***
          *      ** **  ** **  *   *
          *      * * *  * * *  *   *
          *****  *   *  *   *  *****
          *      *   *  *   *  *   *
          *****  *   *  *   *  *   *
 
   3. Schreiben Sie ein Programm, welches die Quadrate und Kuben
      der Zahlen von 1 bis 20 zeigt.
 
   4. Modifizieren Sie das Programm, daß es Quadrate und Kuben
      der ungeraden Zahlen von 1 bis 20 zeigt.
 
   5. Sie haben einen Job angeboten bekommen, wo Sie am 1. Tag nur 1
      Pfennig verdienen, am nächsten aber das doppelte usw. Wieviel
      bekommen Sie insgesamt in 30 Tagen? In Mark und Pfennig?
 
   6. Schreiben Sie ein Programm, welches zeigt, wieviel Geld Sie am
      Jahresende schulden, wenn Sie 1000 DM zu 10 % borgen und 200 DM
      am Jahresende zurückzahlen. Das Programm soll Jahr, Schuld und
      Zinsen an jedem Jahresende zeigen, solange, bis die Schuld
      beglichen ist.
 
   7. Tabellieren Sie (berechnen und ausdrucken) die Werte von
      y= ( x²-x+2 ) / ( x + 3 ) für x=0,1,...,10
 
   8. Tabellieren Sie (berechnen und ausdrucken) die Werte von
      y=3x²-2x+7 für x=1,3,5,...,21
 
   9. Berechnen Sie die Summen von
      0³, 0³+ 1³, 0³+ 1³+ 2³, ... , 0³+ 1³+ 2³+ ...9³ .
      Benutzen Sie den Operator ** für "hoch" (X hoch 3: X**3).
      Drucken Sie die Quadratwurzel jeder Summe aus (Funktion SQRT).
      Welches allgemein gültiges Ergebnis ergibt sich?
 
   10. Die sog. Fibonacci-Zahlen sind 0,1,1,2,3,5,8,..., wobei jede
       Zahl die Summe der beiden vorhergehenden ist. Berechnen Sie
       die ersten 15 Fibonacci-Zahlen.
 
   11. Benutzen Sie den Operator ** (X hoch 2: X**2) zur Berechnung von
           2  4  8  16
       x, x ,x ,x ,x    für x=1.25. Verwenden Sie einen Algorithmus
       mit Schleife.
 
   12. Berechnen Sie für x=1.25 die ersten 8 Glieder der Folge
           3  6  10
       x, x ,x ,x    ... (Man beachte, daß Exponent und Nenner sich
          -- -- ---
           3  6  10        jeweils um 2,3,4,... vergrößern)
 
 
 
 
 
 
 
   -  20 -        Kapitel 2: Zahlen, Arithmetik und Variablen         -  20 -
 
 
                  Kapitel 2: Zahlen, Arithmetik und Variablen
                  ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
           Fragen
 
   1. Wie werden INTEGER-Zahlen und REAL-Zahlen definiert und benutzt?
   2. Wie sind die Regeln für die Berechnung arithmetischer Ausdrücke?
   3. Wie werden Variable definiert?
   4. Wie sehen die beiden Methoden aus, Variablen einen Wert zu geben?
 
           Ganze Zahlen (INTEGER)
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   INTEGERs bestehen aus Ziffern ohne Dezimalpunkt, evtl. mit vorange-
   stelltem Vorzeichen, z.B. 123    -4375  +2  0
   Der Zahlenbereich für INTEGER-Zahlen ist 2147483647 ... -2147483648;
   oder -2hoch31, -2hoch31 +1,...,-1,0,1,..., 2hoch31 -1
 
   Mit INTEGERs können folgende Operationen ausgeführt werden:
        +   Addition
        -   Subtraktion
        *   Multiplikation
        /   ganzzahlige Division zweier INTEGERs (Ergebnis INTEGER)
            der Divisionsrest geht verloren
        **  Exponentiation
   Es gelten die üblichen Rechenregeln, wobei aber bei / ganzzahlig
   der gebrochene Teil des Ergebnisses verschwindet (ohne Rundung).
 
   Prioritäten bei der Auswertung:
   1. Funktionen
   2. Klammern (innerste zuerst)
   3. **      von rechts nach links
   4. * /     von links nach rechts
   5. + -     von links nach rechts
 
   Beispiele für das Rechnen mit INTEGERs:
       3+2*4        ->   11
       5+2**3*7     ->   61
       -4**2        ->  -16
       4**2**3      ->   65536
       5/2          ->   2
       5/-2         ->   *ERR* - richtig ist 5/(-2)  ->  -2
       3*5/4*3      ->   9
       1234**50     ->   0  !!  der gültige Zahlenbereich
                           von ca. 2 Mrd. wird überschritten
 
            Übungen
            ¯¯¯¯¯¯¯
   1. Schreiben Sie den folgenden Ausdruck um, indem Sie so viele
      Klammern wie möglich entfernen, ohne den Wert zu ändern:
             ((-(5*2)**3)+(14/(2**(-3))))
   2. Schreiben Sie einen INTEGER-Ausdruck mit dem Wert 20
      a) mit 1 Multiplikation und 1 Subtraktion
      b) 3 Divisionen
      c) 1 Exponentiation, 1 Division und 1 Addition
      d) 2 Klammerpaaren (die auch notwendig sind)
      e) 2 Exponentiationen und 1 Division
 
           Zahlen mit Dezimalpunkt (REAL)
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   REAL-Zahlen bestehen in Fortran aus 3 Teilen:
    1. dem ganzzahligen Teil
    2. dem gebrochenen Teil (wahlweise)
    3. dem Exponent (wahlweise)
   -  21 -        Kapitel 2: Zahlen, Arithmetik und Variablen         -  21 -
 
   REAL-Zahlen bestehen aus dem gebrochenen Teil der REAL-Zahl, z.B. 7.375,
   und wahlweise einem Exponenten E und einer ganzen Zahl mit Vorzeichen.
   Doppeltgenaue REAL-Zahlen müssen den Exponenten D mit sich führen.
 
   Beispiele z.T. mit Fehlern (***):
       2,457.21      Komma nicht erlaubt                   ***
       -7.           gebrochener Teil der REAL-Zahl kann wegbleiben
       .735          ganzzahliger Teil der REAL-Zahl kann wegbleiben
       92.4E3.8      Exponent hinter E muß ganzzahlig sein ***
 
   im Programmm:     ergibt mit PRINT*, PC      mit PRINT*, Workstation
       7.375                    7.3750000             7.375000000
       -0.00621E-3             -6.2100000E-006        -0.6209999810E-05
       897524.0E27              8.9752400E+032        0.8975240144E+33
       0.0                      0.0000000             0.0000000000E+00
       1.23456789012345         1.2345680             1.234567881
       1.23456789012345D0       1.234567890123450     1.23456789012345003
   Der Exponentenbereich für REAL-Zahlen ist für PC und Workstation
   -38 ... +38 (REAL einfach genau) bzw. -308 ... +308 doppelt genau.
   Dazu kommen ca. 7 bzw. 15 Dezimalen (ganzzahliger und gebrochener Teil).
   Dies entspricht dem sog. IEEE-Standard.
   Die 5 REAL-Grundrechenarten haben dieselbe Priorität wie bei INTEGER.
   Die Division wird mit demselben Zeichen gechrieben wie bei INTEGER:
    / : REAL-Division mit mind. 1 REAL, evtl. 1 INTEGER (Ergebnis REAL)
   Beispiele:
   im Fortranprogramm:        PRINT*, am PC      PRINT*, an der Workstation
      10.0 / 5.0 + 3.56       5.56                     5.559999943
      6.25-3.0**2.0           -2.75                    -2.750000000
      -30.0/8.0/100.0         -0.0375                  -0.3750000149E-01
      -2.0**6.0               -64.                     -64.00000000
      2.25/15.0*(-0.6)        -0.9                     -0.9000000358E-01
      3.0*(3.0**2.0/8.0-1.0)  0.375                    0.3750000000
      2**32                   0              !!        0
      2**31                   -2147483648              -2147483648
      2.0**31                 2.1474840E+009           0.2147483648E+10
      2D0**32                 4294967296000000D+009    4294967296.00000000
      (-2.0)**3               -8.0000000               -8.000000000
      (-2.0)**3.0             *ERR*                    -8.000000000
   Am PC versucht es der Compiler über Logarithmen, was mit -2. nicht geht.
 
   Werden die arithmetischen Operatoren (+,-,*,/) auf eine REAL- und
   eine INTEGER-Zahl angewandt, wird die Integer-Zahl vorher in REAL
   umgewandelt - "gemischte Arithmetik": vergl. mit oben:.
      10.0 / 5 + 3.56  -> 5.560000  (PC; 5.559999943 an der Workstation)
            2. Zahl ist INTEGER, gerechnet wird also 10.0 / 5.0
 
   Regel: Vermeiden Sie wo möglich gemischte Arithmetik:
          benutzen Sie in 1 Anweisung durchweg INTEGER oder durchweg REAL
   Ausnahme: 2.0**3 : ganzzahliger Exponent immer als INTEGER schreiben!
 
           Konstante, Variable
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Konstante sind Zahlen, z.B. "0.1"  (auch Strings, s. später), die während
   der Ausführung des Programms gleich bleiben. Variable sind Größen, die
   unterschiedliche Werte annehmen können.
   Die Benutzung einer Variablen geht in 3 Schritten:
   1. Auswahl eines gültigen Namens
   2. Mitteilung an den Compiler, um welchen Typ es sich handeln soll
      (z. B. INTEGER, REAL, CHARACTER usw.) "Typ-Deklaration"
   3. Zuweisung eines Wertes, bevor ein Wert entnommen wird. Dies ist
      grundsätzlich auf 2 Arten  möglich:
      a) Zuweisungsanweisung (Anweisung der Form Variable = Ausdruck)
      b) Einlesen eines Wertes mit der READ-Anweisung, s.u.
   -  22 -        Kapitel 2: Zahlen, Arithmetik und Variablen         -  22 -
 
       ________________________________________________________________
      |        Fortran-Namen:                                          |
      | 1. Maximale Länge: 6 Buchstaben oder Ziffern (Fortran77)       |
      |    Die meisten Compiler gestatten längere Namen (31 Zeichen)   |
      | 2. Erstes Zeichen ein Buchstabe                                |
      | 3. weiter mit Buchstaben oder Ziffern, keine Sonderzeichen     |
      | 4. Blanks sollen innerhalb eines Namens nicht verwendet werden |
      |________________________________________________________________|
 
    Beispiele: gültig   zu vermeiden  mehr als 6 Zeichen  ungültige Namen:
               MUTTER                                       9D
               REAL          *                              A(I
               RR2                                          RR#2
               NETPAY                     Mueller           NET-PAY
               A9A9                       Net_Pay
 
   Regel: vermeiden Sie Namen (s.o. *), die schon eine andere Bedeutung
          in Fortran haben, also z.B. INTEGER, REAL, WHILE usw.!
   Anmerkung: Die meisten Compiler akzeptieren auch Kleinbuchstaben und das
              Unterstreichungszeichen (wie im Fortran90-Standard).
 
           Erklärung des Typs ( Deklaration )
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   1. Art: Voreinstellung der Typen: ohne Deklaration nimmt Fortran
           folgende Typen an ("Erste-Buchstaben-Regel"):
              Ist der 1. Buchstabe I,J,K,L,M,N : INTEGER; sonst REAL
   2. Art: explizite Deklaration des Typs:
           INTEGER A,Ops,Prt,ZZ,Sum
           REAL N,J96,I,BAF
           REAL*8 D                  REAL mit doppelter Genauigkeit
 
   Hinter INTEGER und REAL usw.  kein Komma!
   Eine Variable kann nicht 2 Typen, z.B. REAL und INTEGER, besitzen.
   NB: Ausschalten der "Erste-Buchstaben-Regel" erfolgt mit der Anweisung
           IMPLICIT NONE
       unmittelbar hinter der PROGRAM-Anweisung. Empfehlenswert zur
       Vermeidung von Schreibfehlern, da sonst automatisch eine neue
       Variable angelegt wird!
 
           Zuweisung von Werten an Variable
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Die allgemeine Form der Zuweisung ist  variable = wert
 
   Bedeutung: der rechts vom  =  stehende Wert wird berechnet und der
              Variablen auf der linken Seite zugewiesen.
   Beispiele:    A      = 3.0 * 8.0 / 2.0**4
                 JJ     = MOM * (3**I + 1)
                 A      = 10
                 L23456 = 3.7
   Dabei sei angenommen, daß die Variablen  MOM und I bereits Werte
   enthalten, ansonsten kann die Anweisung nicht ausgeführt werden.
   Im Fall A=10 wird A die INTEGER-Konstante 10 zugewiesen; in der
   Zeile darunter umgekehrt einer INTEGER-Variablen eine REAL-Konstante.
   In beiden Fällen wird automatisch eine Typumwandlung vorgenommen.
   A erhält den Wert 10.0, L23456 den Wert 3 ( .7 fällt weg!).
 
           Einlesen von Werten
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Das Einlesen eines Wertes gibt einer Variablen denselben Wert wie die
   Zuweisung dieses Wertes im Programm. Der Wert ist jetzt aber nicht
   mehr fester Bestandteil des Programms, sondern kann am Bildschirm
   eingetippt oder vorher in ein Datenfile geschrieben werden.
 
   -  23 -        Kapitel 2: Zahlen, Arithmetik und Variablen         -  23 -
 
   Beispiel 2.1
   ¯¯¯¯¯¯¯¯¯¯¯¯
          PROGRAM P21
   * Beispiel 2.1: Berechnung der Fakultät von n
          INTEGER FakN, Mult, n
          FakN = 1
          Mult = n
          WHILE (Mult .GE.1)
            FakN = FakN * Mult
            Mult = Mult - 1
          ENDWHILE
          PRINT*,n,' Fakultät =',FakN
          END
 
   Damit erhalten Sie die Meldung *ERR* UV-05 the value of N is undefined
   Setzen Sie hinter der Zeile "INTEGER ..." die zwei Anweisungen ein:
         PRINT*,'bitte Wert fuer n eingeben'
         READ*,n
   Sie werden dann am Bildschirm gefragt und tippen die gewünschte Zahl
   für N ein; anschließend die Enter-Taste.
 
   Die allgemeine Form der READ-Anweisung ist:
       ________________________________________________________________
      |        READ*, Eingabe-Liste                                    |
      | Eingabe-Liste:    eine Folge von Variablennamen,               |
      |                   die durch Komma getrennt sind                |
      |________________________________________________________________|
 
   Beispiele:
      READ*, i, y, Var, KK     wartet auf Eingabe von 4 Werten (und Enter)
      READ*                    wartet nur auf Enter
   fehlerhaft wäre:
      READ* x        Komma fehlt
      READ*, 10/a    Ausdrücke sind nicht möglich (jedoch bei PRINT*, )
 
   Regeln für die Schreibweise der Werte für READ:
       ________________________________________________________________
      | 1. Daten sind durch Komma oder Leerzeichen voneinander getrennt|
      | 2. Daten werden nach den Regeln für Konstante geschrieben.     |
      | 3. Reicht der Platz einer Zeile nicht für alle Daten, wird     |
      |    automatisch eine neue Zeile eingelesen, bis alle Variablen  |
      |    der Eingabe-Liste mit Werten versorgt sind.                 |
      | 4. Stehen in 1 Zeile mehr Werte, als in der Eingabe-Liste      |
      |    gebraucht werden, werden diese ignoriert. Sie stehen auch   |
      |    für ein weiteres READ nicht mehr zur Verfügung              |
      | 5. Ein / beendet die Dateneingabe (insbes. am Schirm)          |
      |________________________________________________________________|
 
   Beispiele für die Dateneingabe (am Ende jeder Zeile Enter drücken!):
   Anweisung:                       READ*,x,y,i
   Daten:                           2.0E4, -7.1 67
 
   Anweisung:                       READ*,x,y,i
   Daten in mehr als 1 Zeile:            2.0E4
                                      -7.1          67
 
   2 mal READ hintereinander:       READ*,x,y,i
                                    READ*,j
   Daten:                           2.0E4
                                         -7.1
                                    67.84     25
                                   -18   738
 
   -  24 -        Kapitel 2: Zahlen, Arithmetik und Variablen         -  24 -
 
   J erhält den Wert -18; 25 und 738 werden ignoriert; warum?
   Erklärung: Das 1. READ liest 3 Werte, also bis 67.84; das 2. READ
       geht auf eine neue Zeile, ignoriert also 25; ein weiteres READ
       würde wieder auf eine neue Zeile gehen und 738 ignorieren.
 
   2 Variable, nur 1 Wert (ein / beendet die Dateneingabe):
                                    READ*,i,x
                                    PRINT*,i,x
   Daten:                           3    /
 
   Das PRINT liefert                3    ????????    (2. Wert undefiniert)
 
   Der Vorteil des READ anstelle einer Zuweisung im Programm ist der, daß
   das Programm für verschiedene Werte ein Ergebnis liefert (z.B. das
   Fakultätprogramm für jeden beliebigen eingetippten Wert).
 
   Regel:
   Sobald das Programm auf die Anweisung "READ*,..." trifft, hält es
   an und wartet auf die Eingabe der Daten. Daher sollten Sie vor jedem
   READ* mit PRINT* angeben, welche Daten erwartet werden.
 
           Umlenken der Standard-Ein/Ausgabe
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Wenn man mehr als 24 Ergebniszeilen erzeugt hat, so verschwinden die
   ersten Zeilen über den oberen Rand weg. WATFOR bietet die Option,
   die Ergebnisse statt auf den Bildschirm in das Listing-File zu
   schreiben. Dieses kann man dann editieren und die Ergebnisse ansehen
   oder auch ausdrucken. Starten Sie das Programm mit
      RUN/NOXT  oder  RUN/NOEX/NOXT     bzw. Alt_F3 (programmierte Taste)
 
   So ist jedoch kein Bildschirmdialog möglich, weil z.B. die Aufforderung
   PRINT*,'bitte ... eingeben' ebenfalls im Listing landet (der gewünschte
   Text erscheint nicht am Schirm, nur im Listing).
 
   Wollen Sie beides, starten Sie mit
      RUN/LOgio oder  RUN/NOEX/LOgio    bzw. Alt_F5 (programmierte Taste)
   Jetzt läuft der Dialog am Schirm normal ab; zusätzlich wird aber das
   Ergebnis eines jeden READ* und jede Bildschirmeingabe im Listing-File
   festgehalten!
 
   Für die Eingabe größerer Datenmengen empfiehlt sich jedoch ein anderes
   Verfahren: Mit der OPEN-Anweisung kann das Programm individuell seine
   eigene Einstellung der Geräte-Nr. (s.u. Kap. 7) vornehmen; z.B. richtet
 
           OPEN(1,FILE='P1.DAT')
 
   alle READ(1,*)   -Anweisungen auf das File P1.DAT.
   Die Anweisung READ(1,*) wird also anstelle von READ*, geschrieben.
   Auf diese Weise können die Daten im voraus erstellt werden (Edit auf
   das File), sodaß man sie nicht immer wieder am Schirm eintippen muß.
   Als Geräte-Nr. sind alle Zahlen von 0 bis 99 möglich.
   Verwenden Sie jedoch dabei 5 und 6 nicht, da diese Geräte-Nr. für die
   Bildschirm- Ein- und Ausgabe reserviert sind (Näheres s.u. Kap. 7).
 
   Umgekehrt schreibt WRITE(2,*) in ein File (s.o. OPEN); das bedeutet
   aber, daß alle etwa schon vorhandenen Daten des Files gelöscht werden!
 
   Ist das File des angegebenen Namens auf Disk nicht vorhanden, so wird
   es automatisch angelegt.
 
   Soll der Inhalt eines Files beim WRITE erhalten bleiben, so werden die
   Daten am Ende angefügt (Vorgriff auf den Fortran90-Standard) nach einem
           OPEN(2,FILE='P1.ERG',ACCESS='APPEND')
   -  25 -        Kapitel 2: Zahlen, Arithmetik und Variablen         -  25 -
 
           Eingebaute Funktionen
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Die "INTRINSIC" Funktionen liefern für alle zulässigen Typen von Argu-
   menten automatisch das Ergebnis im richtigen Typ ("Polymorphismus").
   Im folgenden bedeutet I / R / D / C / Z / L / c  ein Argument vom Typ
   INTEGER / REAL / REAL*8 (REAL doppelt genau) / COMPLEX / COMPLEX*16
   (COMPLEX doppelt genau) / LOGICAL / CHARACTER.
 
            Typ Argument  Typ Resultat (x: wie Typ Argument)
                  ||||||  |
   Typ-Umwandlungen:
 
   1. REAL(x)     IRDCZ   R       Umwandlung nach REAL
   2. DBLE(x)     IRDCZ   D       Umwandlung nach REAL*8(DOUBLE PRECISION)
   3. CMPLX(x)    IRDCZ   C       Umwandlung nach COMPLEX
   4. DCMPLX(x)   IRDCZ   Z       Umwandlung nach COMPLEX*16
                                                (DOUBLE PRECISION COMPLEX)
   5. INT(x)      IRDCZ   I       Umwandlung nach INTEGER
   6. NINT(x)      RD     I       Umwandlung nach INTEGER mit Rundung
   7. AINT(x)      RD     x       ganzz. Anteil betragsmäßig <=
                                     (Nachkommastellen abgeschnitten)
   8. ANINT(x)     RD     x       dass. mit Rundung
   9. IMAG(x)        CZ   R,D     Imaginärteil
   10. CONJG(x)      CZ   x       konjugiert komplexe Zahl
   11. CHAR(x)    I       Ch      Umwandlung INTEGER nach CHARACTER
   12. ICHAR(x)        c  I       Umwandlung CHARACTER nach INTEGER
 
   Stringverarbeitung (Näheres s. Kap. 8):
 
   13. LEN(x)          c  I       Länge eines CHARACTER-Strings
   14. INDEX(x,y)      c  I       Position von String y in String x
   15. LGT(x,y)        c  L       Lexikographisch größer ( x > y )
   16. LLT(x,y)        c  L       Lexikographisch größer oder gleich
   17. LGE(x,y)        c  L       Lexikographisch kleiner
   18. LLE(x,y)        c  L       Lexikographisch kleiner oder gleich
 
   Numerische Funktionen:
 
   19. ABS(x)     IRDCZ   x       Absolutwert
   20. MAX(x,...) IRD     x       Maximum von mehreren Werten dess. Typs
   21. MIN(x,...) IRD     x       Minimum von mehreren Werten dess. Typs
   22. MOD(x,y)   IRD     x       1. Argument modulo 2. Argument
                                      ( Divisionsrest von x / y )
   23. SIGN(x,y)  IRD     x       x bekommt das Vorzeichen von y
   24. DIM(x,y)   IRD     x       positive Differenz x-y falls x>y,0 sonst
   25. DPROD(x,y)  R      D       x * y doppelt genau
   26. SQRT(x)     RDCZ   x       Quadratwurzel
 
   Logarithmus, Exponentialfunktion, Trigonometrische Funktionen:
 
   27. EXP(x)      RDCZ   x       Exponentialfunktion
   28. LOG(x)      RDCZ   x       Logarithmus naturalis
   29. LOG10(x)    RD     x       Logarithmus zur Basis 10
   30. SIN(x)      RDCZ   x       Sinus (Winkel im Bogenmaß)
   31. COS(x)      RDCZ   x       Cosinus            "
   32. TAN(x)      RD     x       Tangens            "
   33. ASIN(x)     RD     x       Arcussinus         "
   34. ACOS(x)     RD     x       Arcuscosinus       "
   35. ATAN(x)     RD     x       Arcustangens       "
   36. ATAN2(x,y)  RD     x       Arcustangens (x/y) "
   37. SINH(x)     RD     x       Sinus hyperbolicus
   38. COSH(x)     RD     x       Cosinus hyperbolicus
   39. TANH(x)     RD     x       Tangens hyperbolicus
   -  26 -        Kapitel 2: Zahlen, Arithmetik und Variablen         -  26 -
 
           3 Fehlerquellen bei der Arithmetik mit REAL-Zahlen
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   1. Wir schreiben alle Zahlen im Dezimalsystem; alle Computer (außer
      Taschenrechner) rechnen aber intern im Dualsystem. Wenn nun die
      gegebene Dezimalzahl nicht exakt im Dualsystem darstellbar ist,
      ergibt sich bereits bei der Ein- oder Ausgabe ein Umwandlungsfehler:
      z.B. ist 1/5 nicht exakt dual darstellbar; allg. alle Dezimalzahlen,
      die außer den Anteilen 1/2, 1/4, 1/8 ... auch 1/5, 1/10, 1/25 usw.
      enthalten; z.B.ist 1/5 = 0.00110011... eine unendliche periodische
      Dualzahl; der Computer kann natürlich nur eine gewisse feste Anzahl
      von Dualstellen darstellen: die Genauigkeit ist beim Typ REAL
      24 bit = 7 Dezimalen, REAL*8: 53 bit = 15 Dezimalen (IEEE-Standard).
   2. Durch wiederholte Anwendung der Grundrechenarten werden solche
      Fehler vergrößert; probieren Sie es aus: Addieren Sie 10 mal 0.1;
      es müßte am Ende 1.0 herauskommen. Beispielprogramm:
      (wegen der IF-Anweisung in der Bedeutung von "wenn" s.u. Kap. 3)
         r = 0.
         i = 1
         WHILE (i .LE. 10)
   *            i mal 0.1 in r aufaddiert, müßte dasselbe sein wie i*0.1
           r = r + 0.1
   *Test auf gleich / ungleich:
           IF     (i*0.1  .EQ.  r ) PRINT*, i*0.1, 'gleich',r
           IF     (i*0.1  .NE.  r ) PRINT*, i*0.1, 'ungleich',r
           i = i + 1
         ENDWHILE
   PC: 0.1000000 gleich  0.1000000    WS: 0.1000000015 gleich 0.1000000015
       0.2000000 gleich  0.2000000        0.2000000030 gleich 0.2000000030
       0.3000000 ungleich  0.3000000      0.3000000119 ungleich 0.3000000119
       0.4000000 gleich  0.4000000        0.4000000060 gleich 0.4000000060
       0.5000000 ungleich  0.5000000      0.5000000000 ungleich 0.5000000000
       0.6000000 ungleich  0.6000000      0.6000000238 ungleich 0.6000000238
       0.7000000 ungleich  0.7000000      0.6999999881 ungleich 0.7000000477
       0.8000000 ungleich  0.8000001      0.8000000119 ungleich 0.8000000715
       0.9000000 ungleich  0.9000001      0.9000000358 ungleich 0.9000000954
       1.0000000 ungleich  1.0000000      1.000000000 ungleich 1.000000119
 
   Für den einen Computer sind also die 7 Wertepaare paarweise ungleich,
   was für 0.8 und 0.9 auch sichtbar ist; in allen anderen Fällen führt
   die Rundung bei der Ausgabe zu einem nur scheinbar exakten Ergebnis!!
   Zudem sehen wir, daß weder I*0.1 noch R die Zahl 1 exakt erreichen.
   Auf der Workstation sind die Ergebnisse eher noch verwirrender; klar ist
   nur, daß beide Computer nur 0.1, 0.2 und 0.4 als "gleich" einschätzen.
        Alles in allem ein niederschmetterndes Ergebnis?!
   Besser hätten wir also geschrieben:
   *Test: falls Absolutbetrag der Differenz kleiner als .00001 drucke ...
           IF( ABS(i*0.1 - r) .LT. .00001) PRINT*,i*0.1', wird mit einem
       & Fehler von weniger als 0.00001 erreicht'
       _________________________________________________________________
      | Regel: REAL-Zahlen nie auf Gleichheit oder Ungleichheit prüfen  |
      | also nicht    IF ( A.EQ.B ) oder IF ( A.NE.B )                  |
      | (es sei denn, man weiß genau, daß beide ganze Zahlen sind)      |
      | statt dessen  IF( ABS(A-B) .LT. 0.0001)                         |
      |   --> 0.0001 stellt eine relativ zum Testwert B kleine Zahl dar,|
      |   etwa 3-4 Zehnerpotenzen kleiner als A, falls A einfach genau  |
      |   etwa 10 Zehnerpotenzen kleiner als A, falls A doppelt genau   |
      |_________________________________________________________________|
 
   Man kann davon ausgehen, daß die Anwendung von 1000 Rechenoperationen
   auf dieselbe Variable einen Verlust von 1 bis 2 Dezimalen mit sich
   bringt, im ungünstigsten Fall sogar 3 Dezimalen, wenn die Fehler nicht
   statistisch verteilt sind, sodaß sich diese z.T. wieder ausgleichen,
   sondern alle Fehler in dieselbe Richtung gehen wie im Beispiel oben.
   -  27 -        Kapitel 2: Zahlen, Arithmetik und Variablen         -  27 -
 
 
   3. Fehler 3. Art:
      Betrachten Sie die beiden Zeilen
      a) PRINT*, 2.0D16 - 2.0D16 + 1.0
      b) PRINT*, 2.0D16 + 1.0 - 2.0D16
      Mathematisch ist das Ergebnis dasselbe; der Computer rechnet jedoch
      nur mit 15 Dezimalen = doppelte Genauigkeit; jeder | soll eine
      der vorhandenen Dezimalen markieren:
 
          ||||||||||||||||               ||||||||||||||||
      a)  20000000000000000.0       b)   20000000000000000.0
       -  20000000000000000.0          +                 1.0
          -------------------            -------------------
                          0.0            20000000000000000.0
       +                  1.0          - 20000000000000000.0
          -------------------            -------------------
                          1.0                            0.0
 
      Die Addition von 1.0 im Fall b) hat keine Wirkung, da nur 15
      Dezimalen verwendet werden. Es kann also jedes Ergebnis, das
      etwa bei 1 liegt, durch Addition von 1.0E16 oder mehr und nachfol-
      gender Subtraktion desselben Betrages zerstört werden!!
      Diesen Effekt nennt man Auslöschung; er ist bei den Numerikern
      ungeheuer gefürchtet, weil mit einem Schlag beliebig viele Dezimalen
      an Genauigkeit verschwinden können, ohne daß der Computer davon
      Meldung macht (eine in meinen Augen unverzeihliche Nachlässigkeit
      der Computerhersteller gegenüber nichtkaufmännischen Anwendungen).
      Daher die (meist kaum exakt zu befolgende) Regel:
       ________________________________________________________________
      | Man vermeide, wenn irgend möglich, daß Zwischenergebnisse      |
      | um mehrere Zehnerpotenzen größer als das Ergebnis sind,        |
      | falls dabei Subtraktionen dieser größeren Beträge auftreten    |
      | können. Sonst Gefahr der Auslöschung beliebig vieler Dezimalen.|
      |________________________________________________________________|
 
   Multiplikation und Division sind im Vergleich relativ harmlos.
 
           Aufgaben
           ¯¯¯¯¯¯¯¯
   1. Berechnen Sie den Wert von 12-(6-i) für i=1,2,...,12. Es sollten 12
      Zeilen Ausgabe erzeugt werden, nämlich i und der entspr. Wert.
   2. Tabellieren (berechnen und ausdrucken) Sie x und y aus der Formel
         x³ -4x² + x - 3
     y = ---------------   für  b) x=-1,-3,...,-11,-13
           | x + 2 |            c) x=10,9,...,-1
   3. Lesen Sie X und N ein. Drucken Sie X, X/2, X/4,...,x/2**N
   4. Berechnen Sie die Summe der ersten N ganzen Zahlen der ersten N
      Quadratzahlen, ..., Summe der N**5 für N=20 mit Hilfe der Formeln
      a) Summe der N:    n(n+1) /2
      b) Summe der N**2: n(n+1)(2n+1) /6
      c) Summe der N**3: n**2 (n+1)**2 /4
      d) Summe der N**4: n(n+1)(2n+1)(3n**2+3n-1) /30
      e) Summe der N**5: n**2 (n+1)**2 (2n**2+2n-1) /12
   5. Eine Näherungsformel für die Quadratwurzel für x im Bereich
      von .1 ... 10 ist (1+4x)/(4+x). Berechnen Sie die Näherung für
      x= .5,1.,...,9.5, vergleichen Sie mit dem wahren Wert und berechnen
      Sie den prozentualen Fehler.
   6. Für den dekadischen Logarithmus im Bereich .1 ... 1.:
      log10 x = -.076 + .281x - .238 /  ( x + .15 )
      Für x=.2,.4,...,1. berechnen Sie den Absolutwert der Differenz der
      Näherung mit dem richtigen Wert.
   7. Gesucht ist die kleinste Zahl der benötigten Geldscheine, um die
      Summe von 1575.00 DM auszuzahlen (eine Schleife ist nicht nötig).
   -  28 -      Kapitel 3: Entscheidungen und Steueranweisungen       -  28 -
 
 
                Kapitel 3: Entscheidungen und Steueranweisungen
                ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
           Fragen
 
   1. Wie wird eine Bedingung als wahr oder falsch erkannt, wie wird sie
      zur Steuerung (engl. control) des Programmablaufs verwendet?
   2. Wenn es mehrere verschiedenen Fälle gibt, wie stellt man es an, die
      entsprechenden verschiedenen Programmstücke auszuführen?
   3. Wie können Anweisungen in einer anderen als der normalen, der
      sequentiellen Reihenfolge ausgeführt werden?
   4. Welche weiteren Möglichkeiten gibt es, eine Entscheidung zu treffen?
 
           Logische Ausdrücke
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Logische Entscheidungen werden häufig getroffen, indem etwa X .LE. 3
   geprüft wird mit dem Ergebnis wahr oder falsch. Logische Ausdrücke
   können folgende Vergleichs-Operatoren enthalten:
     .LT.     .LE.     .EQ.    .GE.     .GT.     .NE.       für
     kleiner  kleiner  gleich  größer  größer  ungleich
              oder             oder
              gleich           gleich
 
   Logische Operatoren haben geringere Priorität als die arithmetischen
   Operatoren (+,-,* usw.); d.h. als erstes wird gerechnet, dann erst
   verglichen; z.B. ist       IF (  x+1  .LE.  2+3  )
   gleichbedeutend mit        IF ( (x+1) .LE. (2+3) )
 
           Der IF-Block
           ¯¯¯¯¯¯¯¯¯¯¯¯
   Beispiel 3.1
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Berechnung der Werte von y=1/(x-2) für x=0,1,...,10
   Für x=2 wäre eine Division durch 0 zu vermeiden.
   Also: falls x=2    dann  drucke "y ist undefiniert für x=2"
         IF( x.EQ.2 ) THEN
           PRINT*, 'y ist undefiniert für x=2'
         ENDIF
 
   Algorithmus:
   NB: die GOTO-Anweisung "GOTO n" setzt bei der Anweisung mit Nr. n fort,
       n steht in den Spalten 1-5 und kann 1 bis 5 Ziffern enthalten.
 
     1. setze x=0                       x = 0.
     2. wenn x >= 10 fertig          20 IF ( x .GT. 10.0) GOTO 30
     2.1. falls x=2                     IF ( x .EQ. 2.0) THEN
                    drucke ...            PRINT*,'y ist undefiniert: x=',x
     2.2. sonst                         ELSE
                berechne y=...            y = 1.0/(x-2.0)
                                        ENDIF
     2.3. addiere 1 zu x                  x = x + 1.0
     2.4. wiederhole ab 2.              GOTO 20
     3. ende                         30 END
 
   Zur IF-Anweisung  IF (...) THEN gehört mindestens noch die Anweisung
   ENDIF(evtl. auch ELSE) dazu. Deshalb nennt man das Ganze den IF-Block.
 
   IF Kurzform:  IF ( Bedingung ) Anweisung
   anstelle von       IF ( Bedingung ) THEN
                         Anweisung
                      ENDIF
   z.B. (s.o.)  IF ( X .GT. 10.0 ) GOTO 30
 
   -  29 -      Kapitel 3: Entscheidungen und Steueranweisungen       -  29 -
 
   IF - THEN - ELSE  allgemeine Form:
       ________________________________________________________________
      | IF - THEN - ELSE (IF-Block):   Programmfluß falls log.Ausdruck |
      |                                        true       false        |
      | IF ( logischer Ausdruck ) THEN            T           F        |
      |    ...  Anweisungen fuer den       ...|<<<<           :        |
      |    ...  Fall true                  ...|               :        |
      |    ...                             ...|>>>>           :        |
      | ELSE                                      :           :        |
      |    ...  Anweisungen fuer den              :    ...|<<<<        |
      |    ...  Fall false                        :    ...|            |
      |    ...                                    :    ...|>>>>        |
      | ENDIF                                     :           :        |
      |    ...                             ...<<<<<    ...<<<<<        |
      |________________________________________________________________|
 
   Die Anweisungen IF, ELSE und ENDIF stehen senkrecht übereinander;
   die inneren Anweisungen eingerückt.
 
   Beispiel 3.2
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Welcher Wert wird durch das folgende Programm ausgegeben?
        i = 2
        IF(i*2 .LT. -2*i) THEN
          PRINT*,i-3
        ELSE
          j = i + 5
          PRINT*,j
        ENDIF
   Der logische Ausdruck ist falsch, die THEN-Gruppe wird ignoriert: 7
 
   Beispiel 3.3
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Es sind die folgenden 4 Intervalle definiert:
   <.........|............|.............|.........>
             0           15            30
      I1: x<=0  I2: 030
 
   Gegeben ein bel. Wert x; gesucht das Intervall, in welchem x liegt.
 
   Methode 1: Intervallhalbierung
     Wir wählen einen Wert, der unterscheidet zwischen einerseits
     I1 und I2, andererseits I3 und I4:
     1.     Lies x
     2.     Wenn x<=15 dann
      .1        ist x in I1 oder in I2
            sonst
      .2        ist x in I3 oder in I4
     3.     Drucke x und das Intervall
     4.     Ende
   Die Unterscheidung zwischen I1 / I2 und I3 / I4 geschieht wieder
   mit je einem IF THEN ELSE; also:
     1.     Lies x                              READ*,x
     2.     Wenn x<=15 dann (I1 oder I2)        IF(x.LE.15) THEN
     2.1        wenn x<=0 dann                    IF(x.LE.0.0) THEN
        .1         ist x in I1                      i=1
                sonst                             ELSE
        .2         ist x in I2                      i=2
                                                  ENDIF
     2.2    sonst (I3 oder I4)                  ELSE
                wenn x<=30 dann                   IF(x.LE.30.0) THEN
        .1         ist x in I3                      i=3
                sonst                             ELSE
   -  30 -      Kapitel 3: Entscheidungen und Steueranweisungen       -  30 -
 
        .2         ist x in I4                      i=4
                                                ENDIF
     3.     drucke x und das Intervall          PRINT*,x,' liegt in I',i
     4.     Ende                                END
 
   Methode 2: Salamitaktik
     Wir sehen zuerst, ob x in I1 liegt; dann ob in I2 usw.:
     1.     Lies x                              READ*,x
     2.     wenn x<=0 dann                      IF(x.LE.0.0)THEN
      .1        ist x in I1                       i=1
      .2    sonst (I2 oder I3 oder I4)          ELSE
                wenn x<=15 dann                   IF(x.LE.15.0)THEN
        .1         ist x in I2                      i=2
        .2      sonst (I3 oder I4)                ELSE
                   wenn x<=30 dann                  IF(x.LE.30.0)THEN
          .1          ist x in I3                     i=3
          .2       sonst                            ELSE
                      ist x in I4                     i=4
                                                ENDIF
 
     3.     Drucke x und das Intervall          PRINT*,x,' liegt in I',i
     4.     Ende                                END
 
   Das Einsetzen von weiteren IF-Blöcken in einen IF-Block nennt man
   Schachtelung. Die Tiefe der Schachtelung ist in unserem Beispiel
   maximal 3.
   Fortran bietet die Möglichkeit, im obigen Beispiel die Schachtelung
   zu vermeiden:
 
   Methode 3: ELSEIF - sonst wenn:
       1.     Lies x                              READ*,x
       2.     wenn x<=0 dann                      IF(x.LE.0.0)THEN
        .1        ist x in I1                       i=1
        .2    sonst wenn x<=15 dann               ELSEIF(x.LE.15.0)THEN
                     ist x in I2                    i=2
        .3    sonst wenn x<=30 dann               ELSEIF(x.LE.30.0)THEN
                        ist x in I3                 i=3
        .4    sonst                               ELSE
                        ist x in I4                 i=4
                                                  ENDIF
       3.     Drucke x und das Intervall          PRINT*,x,' liegt in',i
       4.     Ende                                END
 
   Mit ELSEIF können beliebig viele alternative Fälle geprüft werden; im
   ganzen IF-Block wird dann genau 1 Aktion ausgeführt (wenn keine der IF-
   oder ELSEIF-Bedingungen wahr ist, die ELSE-Aktion). Die verschiedenen
   Aktionen sind logisch durch ein exklusives oder verbunden.
 
   Wenn das ELSE ... weggelassen wird, dann gilt nicht mehr, daß genau
   e i n e  Aktion ausgeführt wird. Dies ist aus einem wichtigen Grund
   nicht empfehlenswert:
   Eine Vielzahl von Fehlern in Computerprogrammen kommt daher, daß der
   Programmierer logische Bedingungen übersehen hat oder irrtümlich glaubt,
   diese könnten nie auftreten. Mit ELSE kann man dies ausschließen:
         IF( Bedingung )THEN
             ...
         ELSEIF( Bedingung )THEN
             ...
         ELSE
             PRINT*,'darf nicht sein. wenn doch - Programmierfehler'
         ENDIF
 
 
   -  31 -      Kapitel 3: Entscheidungen und Steueranweisungen       -  31 -
 
   Schreiben Sie also in jedem Fall ein ELSE. Wenn Sie sicher sind, daß
   im ELSE-Fall keine Aktion eintreten soll, so dokumentieren Sie dies,
   indem Sie
         IF ...
            ...
         ELSE
         ENDIF
   schreiben. Die ELSE-Aktion ist hier leer.
       ________________________________________________________________
      | IF - THEN - ELSE (Block-IF):   Programmfluß falls log.Ausdruck |
      |                                  1:true  2:true  3:true  sonst |
      | IF(logischer Ausdruck) THEN          T       :       :       : |
      |    ...  Anweisungen fuer       ...|<<<       :       :       : |
      |    ...  Fall true              ...|          :       :       : |
      |    ...                         ...|>>>       :       :       : |
      | ELSEIF(logischer Ausdruck) THEN      :       T       :       : |
      |    ...  Anweisungen fuer             : ...|<<<       :       : |
      |    ...  2.Fall ( log.A. true )       : ...|          :       : |
      |    ...                               : ...|>>>       :       : |
      | ELSEIF(logischer Ausdruck) THEN      :       :       T       : |
      |    ...                               :       : ...|<<<       : |
      |    ...                               :       : ...|>>>       : |
      | ELSE                                 :       :       :       : |
      |    ...                               :       :       : ...|<<< |
      |    ...                               :       :       : ...|>>> |
      | ENDIF                                :       :       :       : |
      |    ...                            <<<<    <<<<    <<<<    <<<< |
      |________________________________________________________________|
 
           Übungen
           ¯¯¯¯¯¯¯
     1. Schreiben Sie einen oder mehrere IF THEN ELSE -Blöcke, die das
        Ergebnis eines Vergleichs des Wertes von N in Worte fassen, z.B.
        für n=2:  'gleich 2'
             n<>2: 'ungleich 2'
        Lösung:
           IF(n.EQ.2) THEN
              PRINT*,n,'gleich 2'
           ELSE
              PRINT*,n,'ungleich 2'
           ENDIF
     2. a)  n >  MOD(7,n)        'größer'
              <=                 'kleiner gleich'
        b)  5 < n <= 15          'zwischen'
              sonst              'außerhalb'
        c)  n > 50 oder n < -20  'verstreut'
            N >= -20 und N < 0   'Bereich 2'
              sonst              'Bereich 3'
        d) einmal ohne, einmal mit ELSEs:
           N=2                 zwei
           N=4                 vier
           N=6                 sechs
           N=8                 acht
           N=10                zehn
     3. Betrachten Sie die 3 Methoden des obigen Beispiels 3 (4 Inter-
        valle). Nehmen Sie an, daß es gleich wahrscheinlich ist, daß
        x in einem der 4 Intervalle liegt. Welche der 3 Methoden ist am
        effizientesten? Betrachten Sie dazu die durchschnittliche Zahl der
        notwendigen logischen Vergleiche.
 
 
 
 
   -  32 -      Kapitel 3: Entscheidungen und Steueranweisungen       -  32 -
 
           Logische Operatoren
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
     Mit .NOT. für "nicht", .OR. für "oder", .AND. für "und" werden
     logische Ausdrücke gebildet, Klammerung ist ebenfalls möglich; z.B.
     (R1 .AND. R2 .AND. R3 .AND. R4)   true, wenn alle 4 true sind
     (R1 .OR. R2)                      true, wenn auch nur 1 true ist
 
   Es soll x ausgegeben werden, falls x innerhalb des Intervalls (-1,+1):
      IF( x .GE. -1 .AND. x .LE. 1 ) THEN
         PRINT*,'x=',x
      ELSE
      ENDIF
   Es soll x, falls außerhalb des Intervalls, ausgegeben werden:
      IF( x .LT. -1) THEN
         PRINT*,'x=',x
      ELSEIF( x .GT. 1) THEN
         PRINT*,'x=',x
      ELSE
      ENDIF
   Man kann aber die beiden Bedingungen auch so zusammenfassen:
      IF( x.LT.-1 .OR. x.GT.1 ) THEN
         PRINT*,'x=',x
      ELSE
      ENDIF
   oder, wenn Sie an die 1. Version denken (drucken wenn x im Intervall) :
      IF( .NOT. (x.GE.-1 .AND. x.LE.1) ) THEN
         PRINT*,'x=',x
      ELSE
      ENDIF
 
   Prioritäten bei der Auswertung mit logischen Operatoren:
           1. Funktionen (von rechts nach links)
           2. Klammern (innerste zuerst)
           3. Arithmetische Operatoren:
           3.1 **      von rechts nach links
           3.2 * /     von links nach rechts
           3.3 + -     von links nach rechts
           4. Vergleichs-Operatoren (von links nach rechts)
              .LT. .LE. .EQ. .NE. .GT. .GE.
           5. logische Operatoren (von links nach rechts)
           5.1 .NOT.
           5.2 .AND.
           5.3 .OR.
 
           Aufgaben
           ¯¯¯¯¯¯¯¯
   1. Schreiben Sie ein Programm, das einen INTEGER-Wert einliest und
      die Zahl der Ziffern ungleich 0 bestimmt. Hinweis: dividieren Sie
      durch 10, 100, 1000 usw. und sehen Sie zu, ob der Rest 0 ist.
 
   2. Lesen Sie 2 Integers N und M. Lesen Sie einen Wert K. Prüfen
      Sie, ob die letzten K Stellen in M und N dieselben sind. Drucken
      Sie 'die letzten ... Stellen von ... und ... sind gleich' bzw.
      '... ungleich'.
 
   3. Lesen Sie die 3 Seitenlängen eines Dreiecks ein. Drucken Sie
      '0', wenn die Längen kein Dreieck bilden, '1' wenn alle Seiten
      ungleich sind, '2' bei gleichschenkligem, '3' bei gleichseitigem
      Dreieck.
 
 
 
 
   -  33 -      Kapitel 3: Entscheidungen und Steueranweisungen       -  33 -
 
   4. Man berechne die Wurzel aus 12; sie liegt zwischen 3 (low) und 4
      (high); man drucke l und h aus und halbiere das Intervall (3...4),
      d.h. man nimmt (h+l)/2; nun sieht man, ob das Quadrat dieses Wertes
      größer oder kleiner als 12 ist; im ersteren Fall nimmt man den
      Wert als neues h, im anderen als neues l usw., bis der wahre Wert
      bis auf 0.01 angenähert ist (bis sich h und l um weniger als 0.02
      unterscheiden): die Wurzel aus 12 liegt zwischen h und l, wenn
      wenn h**2 > 12, l**2 < 12 ist. Man vergleiche mit SQRT(12).
 
   5. Der Wochentag kann für ein bel. Datum aus Jahr (J), Monat (M)
      und Tag (T) mit folgender Formel gefunden werden:
 
      Wochentag = K MOD 7  mit
                                3M +3       J    J
                  K = T + 2M  + ----- + J + - + --- + 1
                                  5         4   100
      Alle Divisionen sind ganzzahlig (Division von Integer-Zahlen).
      Januar und Februar müssen als Monat 13 und 14 des alten Jahres
      aufgefaßt werden.
      Wochentag 0 ist Montag usw.
      Geben Sie verschiedene Daten (Ihren Geburtstag) an; stoppen Sie
      mit einem negativen Jahr.
 
   6. Drucken Sie alle ganzen Zahlen zwischen 100 und 500 aus, die lauter
      verschiedene Ziffern enthalten. Man drucke je 4 Zahlen pro Zeile.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
   -  34 -                    Kapitel 4: Schleifen                    -  34 -
 
 
                              Kapitel 4: Schleifen
                              ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
           Fragen
 
   1. Was ist eine Schleife?
   2. Wie sehen die beiden Arten von Schleifen in Fortran aus?
 
           Schleifen und Schleifensteuerung
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   In Kap. 1 hatten wir Algorithmen, wo eine oder mehrere Anweisungen
   mehrfach ausgeführt wurden. Diese Art von Wiederholung nennt man eine
   Schleife. Die Steuerung der Schleife, d.h. die Logik, mit der die
   Ausführung der Schleife gesteuert wird, dh. unter welchen Bedingungen
   die Schleife ausgeführt, unter welchen abgebrochen wird, ist Teil der
   Anweisung, z.B. in (...) bei der Anweisung WHILE (...), oder wird
   in Form weiterer Bedingung(en) in der Schleife geschrieben, s.u.
   Wird sie nie abgebrochen, spricht man von einer  Endlosschleife.
 
           WHILE-Schleife
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Die WHILE-Schleife besteht aus 4 Teilen:
   1. Eine Anweisung zum Setzen des Ausgangswertes für den logischen
      Ausdruck der WHILE-Anweisung.
   2. Die WHILE-Anweisung, in Klammern ein logischen Ausdruck. Ist er
      wahr, werden die unmittelbar folgenden Anweisungen (die Schleife)
      ausgeführt. Ist er falsch, geht es hinter ENDWHILE weiter.
   3. Das Innere der Schleife muß eine Anweisung enthalten, die irgendwann
      den logischen Ausdruck falsch macht (Beenden der Schleife).
   4. ENDWHILE als letzte Schleifenanweisung.
 
   Beispiel 4.1
   ¯¯¯¯¯¯¯¯¯¯¯¯
         N = 1                                 Setzen Anfangswert
         WHILE ( N .LE. 10 )                   Bedingung für Ausführung
           PRINT*,N                              beliebige Aktion
           N = N + 1                             notwendig für Beenden
         ENDWHILE                              markiert Schleifenende
 
       WHILE - Schleife allgemeine Form:
       ________________________________________________________________
      |    WHILE:                      Programmfluß falls log.Ausdruck |
      |                                        false      true         |
      | WHILE ( logischer Ausdruck )           >>>>>      />>>>        |
      |    ...  Anweisungen der Schleife           :      /   ...      |
      |    ...                                     :      /   ...      |
      | ENDWHILE                                   :      /<<<<        |
      | ...     Fortsetzung                  ...<<<<                   |
      |________________________________________________________________|
 
      NB: Die WHILE-Schleife ist ein Vorgriff auf den Fortran90-Standard
           DO WHILE ( ... ) ... ENDDO
 
           Übungen
           ¯¯¯¯¯¯¯
   1. Sehen Sie sich die folgenden Programme an. Keines läuft ohne Fehler.
      Erklären Sie, warum.
   a)      x = 1
           WHILE(x .LE. 10)             b)    WHILE(x*2 .GT. 5)
             PRINT*,x                           PRINT*,x
             PRINT*,3*x+2                       x = x - 1
           ENDWHILE                           ENDWHILE
           END                                END
   -  35 -                    Kapitel 4: Schleifen                    -  35 -
 
   c)      x = 10                       d)    x = 1
           WHILE(x**2 .GE. 100)               WHILE(x .LE. 10)
             x = x + 1                          PRINT*,x
           ENDWHILE                             x = x + 1
           PRINT*,x,x**2                      END
           END
   2. Die Regeln für WHILE sind:
      (1) Die Bedingung im WHILE muß vorher gesetzt werden
      (2) Die Bedingung im WHILE muß irgendwann einmal false werden
      (3) Das Innere der Schleife wird abgeschlossen mit ENDWHILE
      Welche der 3 Regeln ist in den 4 Programmen oben verletzt?
 
           DO-Schleife
           ¯¯¯¯¯¯¯¯¯¯¯
   Oft möchte man eine Schleife entweder eine feste Anzahl oder eine
   maximale Anzahl von Malen durchlaufen. Dies kommt so häufig vor, daß
   Fortran eine besondere Anweisung dafür bereitstellt (obwohl alles auch
   mit der WHILE-Schleife gemacht werden könnte).
 
   Beispiel 4.2
   ¯¯¯¯¯¯¯¯¯¯¯¯
         PROGRAM P42
   * Beispiel 4.2: Wie Beispiel 1.3 (Kap.1), aber jetzt mit DO-Schleife
         REAL Kapital, Zinsertrag
         INTEGER Jahr
         Kapital = 100
         DO Jahr = 1991, 2000, 1
           Zinsertrag = Kapital * 0.12
           PRINT*,'Kapital',Kapital,'            Zinsertrag',Zinsertrag
           Kapital = Kapital + Zinsertrag
         ENDDO
         END
 
   Erklärung:
      Die DO-Anweisung setzt zunächst Jahr auf 1991; dann wird getestet,
      ob dieser Wert kleiner oder gleich 2000 ist: ",2000" . Wenn also
      2000 noch nicht überschritten ist, werden die Anweisungen der
      Schleife ausgeführt. Dann wird der Wert von Jahr um 1 erhöht: ",1"
      und der Test wiederholt, bis der Wert von Jahr größer als 2000 ist.
 
   Beispiel 4.3 (Quadratwurzel der positiven Zahl X):
   ¯¯¯¯¯¯¯¯¯¯¯¯
   E sei eine Näherung (positive Zahl), z.B. X/2;
   neues E nach Newton =  Ealt - ( Ealt**2 - X ) / (2*Ealt)
 
   Algorithmus (für DO formuliert):    mit DO:             mit WHILE:
     1. Lies Wert von X                READ*,x             READ*,x
     2. Setze E = X/2                  e = x/2.0           e = x/2.0
                                                           i = 1
     3.0 Wiederhole  10 mal            DO i=1,10,1        WHILE(i.LE.10)
     3.1 Formel für E                    e = ...             e = ...
                                                             i = i + 1
     3.2 oben weiter                   ENDDO               ENDWHILE
     4. Ausdruck der Näherung          PRINT*,e            PRINT*,e
     5. Ende                           END                 END
 
   Vergleichen Sie die logisch gleichwertigen Programme mit DO und mit
   WHILE; Sie sehen die kompaktere Formulierung der DO-Anweisung, wenn
   es sich um einfaches Herauf- (oder Herunter-) -Zählen handelt.
   Die WHILE-Schleife kann demgegenüber allgemeine logische Bedingungen
   zur Schleifensteuerung heranziehen.
 
 
   -  36 -                    Kapitel 4: Schleifen                    -  36 -
 
   Die DO-Anweisung  DO i=1,10,1 besagt:
       Wiederhole alle Anweisungen bis ENDDO wobei der Zähler i anfangs
       1 ist und mit der Schrittweite 1 bis 10 läuft.
   Welche Werte werden mit       DO n=4,24,5          ausgegeben?
                                   PRINT*,n
                                 ENDDO
   Es sind die Werte 4,9,14,19,24: Anfangswert von n ist 4, Schrittweite
   5, Ende, wenn 24 überschritten, d.h. bis einschließlich 24.
 
   Allgemeine Form der DO-Schleife:
       ________________________________________________________________
      |  DO-Schleife ( DO-Block ):                                     |
      |        DO Variable = Anfangswert, Endwert, Schrittweite        |
      |          ...                                                   |
      |          ... (Inneres der DO-Schleife)                         |
      |          ...                                                   |
      |        ENDDO                                                   |
      |                                                                |
      |    Regeln:                                                     |
      | 1. Beim 1. Durchgang hat die DO-Variable den obigen Anfangswert|
      | 2. Falls der Anfangswert größer als der Endwert (wenn die      |
      |    Schrittweite positiv) bzw. kleiner (Schrittweite negativ),  |
      |    wird die DO-Schleife nicht ausgeführt, weiter hinter ENDDO  |
      | 3. Am Ende der DO-Schleife (bei ENDDO) wird zur DO-Variablen   |
      |    die Schrittweite addiert.                                   |
      | 4. Weiter wie unter 2. (Schleife wiederholen oder abbrechen)   |
      | 5. Die Schrittweite (mit vorangehendem Komma) kann entfallen   |
      |    und wird in diesem Fall mit 1 angenommen.                   |
      | 6. Die DO-Variable sowie Anfangswert, Endwert und Schrittweite |
      |    (die DO-Steuergrößen) dürfen innerhalb der DO-Schleife      |
      |    nicht verändert werden.                                     |
      | Besonderheit:                                                  |
      |    Die DO-Parameter sollen vom Typ INTEGER sein                |
      |________________________________________________________________|
 
      NB: Die Schreibweise DO .. ENDDO ist ein Vorgriff auf den
          Fortran90-Standard.
 
   Beispiel 4.4: Zähler läuft rückwärts:
   ¯¯¯¯¯¯¯¯¯¯¯¯
        DO n=10,0,-1    setze Zähler = Anfangswert; schon fertig?
          PRINT*,'n=',n         Aktion
        ENDDO            erniedrige Zähler um Schrittweite; fertig? s.o.
 
   Beispiel 4.5: STOP-Anweisung: Programmende innerhalb der DO-Schleife:
   ¯¯¯¯¯¯¯¯¯¯¯¯
                     ³   ²
   für x=1., 1.5, 2., 2.5, ..., 10. Falls irgendwann durch 0 dividiert
   werden müßte, soll x ausgegeben und das Programm beendet werden.
         REAL x,y,z
   *stattDO x=1.0, 10.0, 0.5 schreiben wir
         DO i=  2,   20,   1
   * und berechnen x mittels Division durch 2:
           x = REAL(i) / 2.0
           z = (5.0*x**3 - x**2 + 4.0*x -7.0)
           IF ( z .EQ. 0.0) THEN
             PRINT*, 'für x=',x,' Division durch 0 -> Programmende'
             STOP
           ENDIF
           PRINT*, 'x=',x,' y=',1.0/z
         ENDDO
         END
 
   -  37 -                    Kapitel 4: Schleifen                    -  37 -
 
           Übungen
           ¯¯¯¯¯¯¯
   1. Betrachten Sie folgendes Programm, ehe Sie die Fragen beantworten:
         DO j = 5 , 100 , 5
           k = j**2
           PRINT*,k
         ENDDO
      Fragen:   a) welcher Wert wird als erstes ausgegeben?
                b) wieviele Werte werden ausgegeben?
                c) was tut das Programm, in Worten ausgedrückt?
                d) welche Änderungen sind nötig, wenn man die Werte
                   25,36,49,64,81,100,121,144 haben will?
   2. Man zähle die 5 in jeder DO-Schleife enthaltenen Informationen auf.
   3. Beschreiben Sie in Worten, was DO J=21,55,2 bedeutet.
   4. Wie oft werden folgende DO-Schleifen durchlaufen:
      a) DO i=2,5
      b) DO j=14,99,14         d) DO Loop=1,1,1
      c) DO k=9,7,2            e) DO Max0=100,203,50
   5. Wo liegt der Fehler?
         DO i=1,12,2
            IF (...) i=i+1
         ENDDO
   6. Geschachtelte DO-Schleifen: Matrix-Multiplikation (s. Kap. 5):
         REAL A(10,10),B(10,10),C(10,10)
   *  C=A*B mit Matrizen A,B,C
         DO i=1,10
           DO j=1,10
             C(i,j)=0.0
             DO k=1,10
               C(i,j)=C(i,j) + A(i,k) * B(k,j)
         ENDDO
      Schreiben Sie das Programm so um, daß die Summierung in einer
      einfachen Variablen ausgeführt wird und C(i,j) erst nach Ende der
      Summierung seinen Wert zugewiesen bekommt (dies ist eine beliebte
      Methode, das Programm schneller zu machen).
 
           Mehrere Endebedingungen in der Schleife
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Zusätzlich zum automatischen Test der Endebedingung der WHILE- bzw.
   DO-Schleife können weitere Tests auf Abbruch folgen.
 
      DO und WHILE mit mehreren Endebedingungen:
       ________________________________________________________________
      |       DO Var=AWert,TWert,Schritt         bzw. WHILE(Bed.)      |
      |         ...                                   .                |
      |         IF (Endebedingung1) GOTO Endnr        wie links        |
      |         ...                                   .                |
      |         IF (Endebedingung2) GOTO Endnr        wie links        |
      |           ...                                 .                |
      |       ENDDO                              bzw. ENDWHILE         |
      | Endnr ...                                                      |
      |                                                                |
      |    Regeln:                                                     |
      | 1. Die Schleife kann von einer beliebigen inneren Stelle aus   |
      |    mit einer Endebedingung verlassen werden (auch mehrere      |
      |    Endebedingungen sind möglich).                              |
      | 2. Die zusätzlichen Endebedingungen verweisen auf die          |
      |    Anweisung unmittelbar hinter ENDDO bzw. ENDWHILE,           |
      |    evtl. auch auf eine wenige Zeilen tiefer stehende Anweisung |
      |________________________________________________________________|
 
 
 
   -  38 -                    Kapitel 4: Schleifen                    -  38 -
 
   Beispiel 4.6: Ausnahmebedingung in einer Schleife:
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Problem:                                 ³    ²
   für x=1.0,2.0,...,10.0, jedoch nur bis zu der Stelle, wo der Nenner 0
   wird: dann soll eine Meldung gegeben und das Programm beendet werden.
   Algorithmus:
   1. Für I=1 bis 10 tue folgendes
   1.0 Schleifensteuerung
   1.1 setze X=I (X ist Real, I Integer!)
   1.2 berechne Nenner nach der Formel
   1.3 WENN Nenner=0,
   1.3.1              gib Meldung
   1.3.2              Programmstop (Ausnahmefall)
   1.4 ANSONSTEN
   1.4.1         drucke Ergebnis
   1.5 nächster Wert I; weiter bei 1.0
   4. Ende
 
      Version mit WHILE:                       Version mit DO:
        x = 1.0                     (1.0)        DO i=1,10
        WHILE( x .LE. 10.0)         (1.0)          x = REAL(I)
          Yn= ...                   (1.2)          Yn = ...
          IF( Yn .EQ. 0.0 ) THEN    (1.3)          IF(Yn .EQ. 0.0) THEN
            PRINT*,'Nenner ist 0'   (1.3.1)          PRINT*,'Nenner ist 0'
            STOP                    (1.3.2)          STOP
          ELSE                                     ELSE
            PRINT*, x, 1.0/Yn       (1.4.1)          PRINT*, x, 1.0/Yn
          ENDIF                                    ENDIF
          x = x + 1.0               (1.5)
        ENDWHILE                    (4.)         ENDDO
        END                                      END
   Am Ende von Kap. 5 finden Sie weitere Ausführungen zu diesem Thema.
 
           Geschachtelte Schleifen
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Beispiel 4.7:
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Problem:       x  - 2xy + y
   berechne z = -------------------- für x=1,1.5,2,...,5; y=30,28,26,...,4
                ( x + 4 ) ( y + 20 )
   Algorithmus:
     1. Setze Schleife an für x=1,...
     1.1 Setze Schleife an für y=4,...
     1.1.1 Berechne z
     1.1.2 Drucke z
     2. Ende
 
    Programm Version 1:
    * geschachtelte Schleifen: X geht ab 1.0 bis 5.0 Schritt 0.5
          DO I = 2,10,1                            ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
            X = I * 0.5                                      äußere |
            DO J = 30,4,-2                         ¯¯¯¯¯¯¯¯|        |
              Y = REAL(J)                                  |        |
              OBEN = X**2 - 2.0*X*Y + Y**2                 |        |
              UNTEN = ( X + 4.0 ) * ( Y + 20.0 )   innere  |        |
              Z = OBEN / UNTEN                     Schleife|        |
              PRINT*,'X=',X,' Y=',Y,' Z=',Z                |        |
            ENDDO                                  ¯¯¯¯¯¯¯¯ Schleife|
          ENDDO                                    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
          END
 
   Ändern Sie den Nenner zu ( x - 4 ) * ( y - 20 ): für x=4 und y=20
   ist der Nenner 0, die Division unmöglich. Geben Sie eine Meldung aus.
   -  39 -                    Kapitel 4: Schleifen                    -  39 -
 
    Programm Version 2:
    *  geschachtelte Schleifen mit neuem Nenner (x-4)*(y-20)
          DO I = 2,10,1                               ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
            X = I * 0.5                                                |
            IF ( ABS ( X - 4.0 ) .LT. 0.0001 ) THEN                    |
              PRINT*,'bei x=' X,' ist der Nenner praktisch 0'          |
            ELSE                                                       |
            DO J = 30,4,-2                            ¯¯¯¯¯¯¯¯¯¯¯¯¯|   |
              Y = REAL(J)                                          |   |
                IF ( ABS ( Y - 20.0 ) .LT. 0.0001 ) THEN           |   |
                  PRINT*,'bei y=' Y,' ist der Nenner praktisch 0'  |   |
                ELSE                                               |   |
                  OBEN = X**2 - 2.0*X*Y + Y**2                     |   |
                  UNTEN = ( X - 4.0 ) * ( Y - 20.0 )               |   |
                  Z = OBEN / UNTEN                                 |   |
                  PRINT*,'X=',X,' Y=',Y,' Z=',Z                    |   |
                ENDIF                                              |   |
              ENDDO                                   ¯¯¯¯¯¯¯¯¯¯¯¯¯    |
             ENDIF                                                     |
          ENDDO                                       ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
          END
 
           Aufgaben
           ¯¯¯¯¯¯¯¯
   1. Tabellieren Sie die Funktion (x**2 - x + 7)/(x**2 +2).
      Schreiben Sie DO-Schleifen für folgende x-Werte:
      a) 1,2,3,...,20  c) 0,-1,-2,...,-8
      b) 3,6,9,...,24  d) 12,10,8,...,-10
 
                                         ³        ³         ²
      für x=-1,-3/4,-1/2,...,1. Übergehen Sie die Fälle mit Nenner = 0.
 
   3. Eine verbesserte Näherung eines Näherungswertes x0 für 1/Wurzel x
      ist X(n) = 0.5 * X(n-1) * ( 3 - X * X(n-1)**2 ).
      Berechnen Sie 1/Wurzel 2  mit Anfangswert 0.4 in 5 Schritten.
 
   4. Nehmen Sie an, daß der Computer nicht dividieren kann. Eine Methode,
      den Wert 1/x nach und nach anzunähern, ist, x0, x1, ... zu berechnen
      mit X  =  X    (2-A*X   ) , x0 ist ein bel. Anfangswert.
           n     n-1       n-1
      Schreiben Sie ein Programm für 1/3 (A=3) und verwenden Sie 0.3
      als Anfangswert. Geben Sie für jede Iteration den x-Wert aus.
 
   5. Man berechne die ersten 15 Fibonacci-Zahlen aus 2 Startzahlen, die
      eingelesen werden; die weiteren ergeben sich jeweils als Summe der
      beiden vorangegangenen. Man lese die Zahlen 0,1 ein.
      Diese Programm schließe man in eine 2. äußere Endlosschleife ein,
      die immer wieder nach 2 Startzahlen fragt. Abbruch mit Strg_z.
      Hinweis: Verwenden Sie WHILE(.TRUE.) .. ENDWHILE als Endlosschleife.
 
   6. Erweitern Sie Aufgabe 8 so, daß bei jedem Durchlauf die Quotienten
      je 2 aufeinanderfolgender Zahlen ausgegeben werden (Typ REAL).
 
   7. Auf einer Party mit n Paaren zieht jede Frau den Namen eines Mannes
      aus einem Hut. Die Wahrscheinlichkeit, nicht den Namen des eigenen
      Partners zu ziehen, ist P  = ( (n-1)/n ) P    + (1/n) P
                               n                n-1          n-2
      wo P0 = 0 und P1= 0.5. Berechnen Sie P für n=2,3,...
 
   8. Lesen Sie einen Wert n=10 ein. Drucken Sie alle Tripel von positiven
      ganzen Zahlen mit Summe n; dasselbe für alle Tripel nicht-negativer
      ganzer Zahlen mit Summe n. Die Tripel sollen durchnumeriert werden.
 
   -  40 -                    Kapitel 4: Schleifen                    -  40 -
 
   9. Tabellieren Sie die Funktion z = (x² - 2xy + 3y³) / (xy+3x+2y+4)
 
      für alle Paare x,y mit x=1,2,...,6 und y=1,2,...5.
 
   10.Nehmen Sie an, der Computer könne nur mit 2 multiplizieren oder
      dividieren (was tatsächlich stimmt!).
      Das Produkt zweier Zahlen kann man dann so bestimmen:
      Man dividiere die kleinere Zahl der Reihe nach durch 2, ohne den
      Rest zu beachten, gleichzeitig wird die größere mit 2 multipliziert.
      Alle Produkte der größeren Zahl werden aufaddiert, falls die
      zugehörige Division ein ungerades Ergebnis geliefert hat.
 
      Beispiel: 37*65 :  37    65
                         18        130  (18 ist gerade)
                          9   260
                          4        520  (4  ...
                          2       1040  (2  ...
                          1  2080
                            +----
      Ergebnis:              2405
 
      Schreiben Sie ein Programm, welches beliebige Zahlenpaare einliest
      und das Produkt nach diesem Verfahren berechnet.
 
      NB: Kleinere Microcomputer benötigen Multiplikationsprogramme dieser
          Art (für Dualzahlen statt wie hier Dezimalzahlen). In größeren
          Computern sind diese als Maschinencode-Befehl fest eingebaut.
 
   11.Auf der Insel Ho leben zwei Rassen - Gute, die immer die Wahrheit
      sagen, und Böse, die immer lügen. Bei meiner letzten Reise
      stellte ich dreien von ihnen, Tom, Dick und Zack, je eine Frage
      (Antwort in Klammern):
      a) Tom, ist Dick ein Guter? (ja)
      b) Dick, gehören Tom und Zack zur selben Rasse? (nein)
      c) Zack, ist nun Dick ein Guter? (ja)
      Schreiben Sie ein Programm zur Bestimmung der Rasse der drei. Dazu
      generieren Sie alle 8 möglichen Kombinationen der Zugehörigkeit zu
      den beiden Rassen (3 DO-Schleifen: Tom,Dick,Zack = true oder false).
      Prüfen Sie jede Kombination, ob sie so antworten würde wie oben.
      Dies kann mit nur 1 IF-Abfrage bewirkt werden! Bedenken Sie, daß
      der Computer nicht denken kann: Sie müssen aus allen theoretisch
      möglichen Antworten die richtigen Schlüsse ziehen.
      Daraus müssen Sie die IF-Anweisung konstruieren.
      Hinweis: Zur Prüfung, ob 2 logische Bedingungen entweder beide
      wahr oder beide falsch sind, gibt es den logischen Operator .EQV.
 
   12.Mit dem Newton-Algorithmus zur Bestimmung der Wurzel (Bsp. 4.3):
      Führen Sie für die Wurzel aus 4059.26   8 Iterationen aus.
      Drucken Sie den Wert der Näherung nach jedem Schritt.
 
   13.Die folgende Aufgabe ist mehr für Naturwissenschaftler geeignet:
      Führen Sie ein anderes Endekriterium statt Zahl der Iterationen ein:
      die Bedingung für die nächste Iteration soll jetzt sein, daß die
      neue Näherung um nicht mehr als 0.0001 von der alten verschieden
      ist. Testen Sie mit x=3.0.
      Den Abbruch der Iteration mit dieser Bedingung können Sie mit der
      QUIT-Anweisung schreiben (Vorgriff auf den Fortran90-Standard, dort
      heißt es EXIT). QUIT verläßt die Schleife (DO- oder WHILE_Schleife)
      und macht direkt hinter ENDDO (oder auch ENDWHILE) weiter.
      Setzen Sie vorher den Iterationszähler auf eine bestimmte maximale
      Zahl. Prüfen Sie, ob das Ende der Iteration durch Erschöpfen der
      Maximalzahl oder durch Erfüllen des neuen Abbruchkriteriums
      zustande gekommen ist.
   -  41 -                     Kapitel 5: Felder                      -  41 -
 
 
                               Kapitel 5: Felder
                               ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
           Fragen
 
   1. Manche der bisherigen Probleme waren mühsam zu programmieren; warum?
   2. Wie können größere Mengen von Variablen definiert werden?
   3. Was versteht man unter der Zuweisung von Anfangswerten?
 
   Beispiel 5.1
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Man lese N (max.6) Werte ein und drucke sie in verkehrter Reihenfolge
   aus. Mit den bisherigen Sprachelementen sieht das so aus (aus Platz-
   gründen stehen mehrere Anweisungen mit ; getrennt auf 1 Zeile):
      READ*,N
      IF(N.GE.1)  READ*,X1; IF(N.GE.2)  READ*,X2
      IF(N.GE.3)  READ*,X3; IF(N.GE.4)  READ*,X4
      IF(N.GE.5)  READ*,X5; IF(N.GE.6)  READ*,X6
      IF(N.GE.6) PRINT*,X6; IF(N.GE.5) PRINT*,X5
      IF(N.GE.4) PRINT*,X4; IF(N.GE.3) PRINT*,X3
      IF(N.GE.2) PRINT*,X2; IF(N.GE.1) PRINT*,X1
      END
 
   Bemerkungen:
    1. Wir müssen alle Werte einlesen, bevor ausgegeben wird.
    2. Für jeden Wert muß eine Anweisung geschrieben werden.
    3. Bei sehr vielen Werten wird das Programm enorm lang; wir benötigen
       ein Verfahren, um die Bezeichnung der Variablen zu verändern.
       Idee:                 Fortran:
                                     REAL X(5)
            READ*,N                  READ*,n
            DO i=1..N                DO i=1,n
              READ*, Xi                READ*, X(i)
            ENDDO                    ENDDO
            DO i=N..1                DO i=n,1,-1
              PRINT*, Xi               PRINT*, X(i)
            ENDDO                    ENDDO
 
    Hier ändert sich der "Name" der Variablen X bei jedem Durchlauf der
    DO-Schleife.
    Wir Schreiben in Fortran  "REAL X(5)" und haben damit ein Feld X
    mit 5 Feldelementen, die X(1), X(2), X(3), X(4), X(5) heißen.
    Man sagt auch "eindimensionales Feld" oder auch Vektor. Die Zahl
    in Klammern heißt Index. Die Angabe 5 in REAL(5) legt die Zahl der
    verfügbaren Feldelemente von X fest; diese Angabe muß eine positive
    ganze Zahl (eine Konstante, keine Variable) sein.
    Ist die benötigte Zahl der Feldelemente nicht bekannt, setze man die
    Dimensionierung auf die größte zu erwartende Zahl.
    z.B. definiert REAL A(20),B,C(1000) genau 1021 REAL-Variable in 2
    Feldern und einer einfachen (skalaren) REAL-Variablen.
 
   Beispiel 5.2
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Man berechne die ersten 15 Fibonacci-Zahlen wie in Aufg. 8 von Kap. 4
   mit 0,1. Man speichere alle Fibonacci-Zahlen in ein Feld ab.
                     INTEGER F(15)
                     F(1)=1
                     F(2)=2
                     DO i=3,15
                       F(i) = F(i-1) + F(i-2)
                     ENDDO
                     PRINT*,F
                     END
   -  42 -                     Kapitel 5: Felder                      -  42 -
 
   Neu sind 2 Dinge:
   1. In der PRINT-Anweisung wird der Feldname F ohne Index verwendet; so
      kann man das ganze Feld drucken (auch bei READ möglich).
   2. Als Indizes sind beliebige INTEGER-Ausdrücke, wie F(I-1), oder auch
      komplizierte REAL-Ausdrücke wie F(2.*LOG(X)/2.) erlaubt.
      Jeder solche Ausdruck wird in den Typ INTEGER umgewandelt und dann
      als Index verwendet - die Regeln sind wie bei der Zuweisung I = R.
   Da die Namen der Feldelemente von F   F(1), F(2),...,F(15) sind, muß
   eine der Zahlen 1 bis 15 herauskommen; kommt z.B. 0 heraus, meldet
   der Compiler     *ERR* SS-04 subscript expression out of range
   Weitere Beispiele: F(F(4))
      Hier ist der Index ein Feldelement desselben Feldes. F(4) ist die
      4. Fibonacci-Zahl, also 3; F(F(4)) ist also hier dasselbe wie F(3).
      Jedoch würde F(F(9)), da F(9)=34 ist, den Fehler "Indexüberlauf"
      erzeugen (bitte ausprobieren und die englische Meldung verstehen!).
 
      F(F(F(6)-2)-3)):
      Dies ergibt  F(F(8-2)-3) = F(8-3) = F(5) = 2
 
   Angenommen, in F und G sind je 20 Elemente gespeichert; wir schreiben
   INTEGER F(20), G(20) und wollen vergleichen, ob dieselben Zahlen
   gespeichert sind. Man kann jedoch nicht schreiben: IF( F .EQ. G ) ..,
   sondern muß die Feldelemente einzeln ansprechen, etwa so:
           DO i=1,20
             IF ( F(i) .NE. G(i) ) THEN
               PRINT*,'F(',i,') ist ungleich G(',i,')'
             ENDIF
           ENDDO
 
           Übungen
           ¯¯¯¯¯¯¯
   1. Betrachten Sie folgendes Programm:
           REAL A(4)
           DO i=1,4
             A(i) = REAL(i)*2.+3.
             PRINT*,A(i)
           ENDDO
           END
   Fragen:
   a) Wird jedem Element des Feldes ein Wert zugewiesen? Warum?
   b) Wieviele der ausgegebenen Zahlen sind Primzahlen?
   c) Warum erscheint keine Fehlermeldung, obwohl die Werte der
      Feldelemente außerhalb des Bereichs 1 bis 4 liegen?
   2. Betrachten Sie die folgenden Anweisungen:
           INTEGER BAC(5)
           DO JKL=1,5
             BAC(6-JKL) = JKL
           ENDDO
   Fragen:
   a) Welcher Wert wird BAC(4) zugewiesen?
   b) Welche Variable hat den Wert 4?
   c) Welchen Wert hat
      aa) BAC(2)/3-BAC(2)
      bb) MOD(BAC(4),3) + MOD(BAC(3),4)
      cc) BAC(4)**BAC(3)**BAC(4)
      dd) BAC(3) - BAC(2) .LT. BAC(1)/4  (wahr oder falsch)
      ee) BAC(BAC(BAC(BAC(1))))
   3. Finden Sie den Fehler in folgenden Zeilen; A und HAPPY seien mit
          INTEGER A(2);   REAL HAPPY(3)        deklariert.
      a)   A(2) = HAPPY(4)
      b)   X    = HAPPY
      c)   J = INT(A(1))
      d)   A = MOD(3.,2.5)
   -  43 -                     Kapitel 5: Felder                      -  43 -
 
   4. Beschreiben Sie ein Feld aus ganzen Zahlen mit Namen Feld mit einer
      DO-Schleife und einer zusätzlichen Anweisung mit den Werten
      a) 2,5,8,11,14,17
      b) -5,-4,-3,-2,-1
      c) -5,-7,-9,-11,-13
      d) 1,3,7,15,31,63
      e) 1,0,1,0,1
      f) 1,0,-1,1,0,-1
 
           Ein- und Ausgabe von Feldern
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Angenommen ein Feld REAL X(6) soll mit Daten versehen werden. Dazu gibt
   es 4 Methoden:
   1.   READ*,X(1),X(2),X(3),X(4),X(5),X(6)    1 READ - mind. 1 neue Zeile
   2.   READ*,X                                Kurzform für 1.
   3.   DO i=1,6
          READ*,X(i)            hier wird READ 6 mal ausgeführt,
        ENDDO                   also werden mind. 6 Zeilen eingelesen
   4.   READ*,(X(i),i=1,6)             äquivalent zu 1 oder 2.
   Letzteres heißt "implizite DO-Schleife". Die Regeln sind dieselben
   wie für DO, nur daß anstelle von DO und ENDDO   ( und )  stehen.
   Allgemeine Form:
   Liste kann eine oder mehrere Variable, Ausdrücke oder Felder enthalten.
   Schrittweite kann entfallen und wird dann als 1 angenommen.
 
           Übungen
           ¯¯¯¯¯¯¯
   1. D und T seien REAL D(16),T(16). Man bestimme Anzahl und Anordnung
     der ausgegebenen Werte:
     a)  PRINT*, T,D
     b)  PRINT*, (T(i),D(i),i=1,16)
     c)  PRINT*, ((D(i+j-1), j=1,4   ), i=1,13,4)
     d)  PRINT*, ((T(i+j-1), j=1,13,4), i=1,4   )
   2. Welche Werte bekommen die Elemente von W?
          INTEGER W(5)
          W(3) = 1
          DO n = 1,2
            W(n+3) = 3-n
            W(3-n) = 3+n
          ENDDO
   3. Formulieren Sie 2 Anweisungen, mit denen 80 Zeichen in 1 Zeile ge-
      schrieben werden, und zwar je 10 Nullen, Einser, Zweier,..., Neuner.
      Verwenden Sie 2 implizite DO-Schleifen. Kann man dies auch mit einer
      erreichen? Oder ohne implizite DO-Schleife?
      Schreiben Sie statt PRINT*,...           WRITE(*,'(80I1)')...
      dies vermeidet die störenden Leerzeichen (s.u. Kap.7).
 
           2-dimensionale Felder - Tabellen
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Wir wollen eine Umfrage in 6 Häusern einer Straße machen und nach der
   Zahl der Vorschulkinder, Grund/Haupt-, Real/Gymnasialschulkinder und
   Erwachsener fragen. Die Ergebnisse tragen wir in eine Tabelle ein:
 
           Vorschule Grund/Hauptschule höhere Schule Erwachsene
   Haus 1      0       1                 2             2
   Haus 2      2       0                 0             2
   Haus 3      0       0                 0             1
   Haus 4      0       2                 0             2
   Haus 5      1       0                 1             2
   Haus 6      0       2                 3             3
 
   Eine rechteckige Tabelle (hier 6 mal 4 Werte) nennt man auch Matrix.
   Jedes Element wird durch Angabe der Zeile und Spalte angesprochen;
   -  44 -                     Kapitel 5: Felder                      -  44 -
 
   z.B. steht in Position (5,2) die Zahl der Grund/Hauptschüler in Haus 5.
   Wenn wir Fragen beantworten wollen wie "In welchem Haus gibt es keine
   Vorschulkinder" oder "Wieviele Erwachsene leben in den 6 Häusern?"
   oder "In welchem Haus wohnen die wenigsten Kinder", dann müssen wir
   jedem der 24 Einträge einen Namen geben, der sich auf die Position in
   dieser Tabelle bezieht. Man schreibt in Fortran: INTEGER T(6,4).
   Damit sind 24 Variable definiert:       T(1,1) T(1,2) T(1,3) T(1,4)
                                           T(2,1) T(2,2) T(2,3) T(2,4)
                                           T(3,1) T(3,2) T(3,3) T(3,4)
                                           T(4,1) T(4,2) T(4,3) T(4,4)
                                           T(5,1) T(5,2) T(5,3) T(5,4)
                                           T(6,1) T(6,2) T(6,3) T(6,4)
   Jede solche Variable nennt man ein zweifach indiziertes Feldelement.
   Der 1. Index bezeichnet die Zeile, der 2. die Spalte. Allgemein ist
   das Element T(i,j) dasjenige in der i-ten Zeile und der j-ten Spalte.
 
   Beispiel 5.3: Statistischer Überblick 1
   ¯¯¯¯¯¯¯¯¯¯¯¯
         PROGRAM P53
   * Das Programm liest die 24 Werte (4 pro Zeile), das Ergebnis
   * ist die Gesamtzahl der Grund/Hauptschüler in allen Häusern.
         INTEGER T(6,4), GSumme
   *  einlesen 24 Werte, 1 Zeile zu je 4 Werten auf einmal
         PRINT*,'Bitte 6 Zeilen zu je 4 Zahlen eingeben'
         DO i=1,6
           READ*, (T(i,j),j=1,4)
         ENDDO
   *  Aufsummieren Grund/Hauptschüler
         GSumme = 0
         DO i=1,6
           GSumme = GSumme + T(i,2)
         ENDDO
   *  Ausdruck Ergebnisse
         PRINT*,'Anzahl aller Grund/Hauptschüler:', GSumme
         END
   Beispiel 5.4: Statistischer Überblick 2
   ¯¯¯¯¯¯¯¯¯¯¯¯
         PROGRAM P54
   * Gefragt ist das Haus mit den meisten Menschen.
         INTEGER T(6,4), Haus, MaxHaus, Max, Einwohner
         PRINT*,'Bitte 6 mal 4 Zahlen eingeben'
         READ*, ((T(i,j),j=1,4),i=1,6)
         Max     = 0
         MaxHaus = 0
         DO Haus = 1,6
   *  Zahl alle Menschen in den Häusern
           EINWO = 0
           DO j=1,4
             Einwohner = Einwohner + T(Haus,j)
           ENDDO
   *  welches ist das meistbewohnte?
           IF ( Einwohner .GT. Max ) THEN
             Max = Einwohner
             MaxHaus = Haus
           ENDIF
         ENDDO
         PRINT*,'Maximalzahl der Einwohner ist',Max,' in Haus',MaxHaus
         END
   Wenn wir die 24 Werte in 6 Zeilen zu je 4 ausdrucken wollen, können
   wir schreiben:              oder in 4 Zeilen mit 6 Werten (spaltenweise)
         DO i=1,6                      DO j=1,4
           PRINT*, (T(i,j),j=1,4)        PRINT*, (T(i,j),i=1,6)
         ENDDO                         ENDDO
   -  45 -                     Kapitel 5: Felder                      -  45 -
 
   Würden wir aber zum Einlesen (entsprechendes gilt auch für die Ausgabe)
         READ*,T
   verwenden, würden die Werte spaltenweise eingelesen, d.h. die ersten 4
   Werte in Spalte 1, die nächsten 4 in Spalte 2 usw.; in diesem Fall
   würde nur das 1. Element T(1,1) und das letzte T(6,4) am richtigen
   Platz stehen. Dasselbe gilt für PRINT*,T. Man sagt auch: Fortran liest
   und schreibt ganze Felder ohne Angabe von Indizes spaltenweise. Dies
   ist bei Verwendung des nackten Feldnamens zu beachten (auch bei DATA!).
 
           Übungen
           ¯¯¯¯¯¯¯
   1. Betrachten Sie die folgende Tabelle:
           2  5  -7  3
           4  8  22  7
           5  9  -6  3
     a) Wieviele Zeilen und Spalten hat die Matrix?
     b) Welches ist das Element in Position (3,2) ?
     c) Welches sind die Positionen der Primzahlen?
     d) Was ist die Summe der Elemente der 2. Zeile, der 3. Spalte?
   2. Nehmen Sie an, A sei ein INTEGER-Feld mit 2 Zeilen, 3 Spalten;
      B mit 3 Zeilen, 2 Spalten.
      a) Deklarieren Sie die Felder.
      b) Welcher Index kann in A auftreten und in B nicht?
      c) Nehmen Sie an, A(i,j) bekommt die Werte i+j für alle i,j und
         B(i,j) entsprechend i-j für alle Elemente.
      ca) Für welche Paare i,j gilt B(i,j)+A(i,j)=2*i ?
      cb) Für welche Paare i,j gilt B(i,j)-A(i,j)=-2*i ?
      cc) Welchen Wert hat A(1,1)*B(1,1)+A(1,2)*B(2,1)+A(1,3)*B(3,1) ?
      cd) Was kommt heraus mit
          PRINT*, ((A(i,j),j=1,3),i=1,1)
          PRINT*, (A(i,k)*B(k,j),k=3,5,4)
          PRINT*, MOD(A(2,i),A(1,i)
      ce) Welchen Wert hat A(B(2,1),A(1,2)  ?
                          B(A(2,B(3,1))-1,B(A(1,B(3,1)),1)) ?
   3. In welcher Reihenfolge erscheinen die Daten? ( Q sei REAL Q(4,2) )
      a)  PRINT*, Q
      b)  PRINT*, (Q(j,1),Q(j,2),j=1,4)
      c)  PRINT*, ((Q(k,num),Q(k+2,num),k=1,2),num=1,2)
      d)  PRINT*, (Q(5-j,2),Q(5-j,1),j=1,4)
   4. Es sei INTEGER X(5,2),Y(2,5). Schreiben Sie 2 DO-Schleifen und eine
      Zuweisung, sodaß Y(i,j) den Wert von X(j,i) erhält. Drucken Sie X
      (5 Zeilen a 3) und Y (2 Zeilen a 5). Sie sehen: die Zeilen von X
      sind genau die Spalten von Y, die Spalten von X die Zeilen von Y.
 
           Höher dimensionierte Felder
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   In Fortran kann ein Feld bis zu 7 Dimensionen haben; in der Praxis
   kommen jedoch selten mehr als 3 vor. Als Beispiel eines 3-dimensionalen
   Feldes stellen Sie sich vor, die Umfrage in den 6 Häusern hätte in 2
   aufeinander folgenden Jahren stattgefunden. Wir schreiben dafür
   INTEGER T(6,4,2), hängen also an unsere alte Dimensionierung hinten
   als 3. Dimension eine 2 an (für die 2 Versionen der Umfrage).
   Schreiben Sie die beiden Beispielprogramme um, indem Sie die 2 mal
   24 Werte einlesen und die Ergebnisse für beide Jahre getrennt ausgeben.
   Tip: Erweitern Sie die Programme,indem Sie das Innere der Programme mit
          DO JAHR=1,2 ... ... ENDDO       umkleiden.
   Bestimmen Sie Haus und Jahr, wo die meisten Menschen gezählt wurden.
 
           Angabe einer unteren Indexgrenze
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Im obigen Beispiel sollten 2 Umfragen, z.B. im Jahr 1986 und 1987,
   erstellt werden. Wir wollen jetzt die Jahreszahlen direkt als Index
   verwenden (anstelle von 1 und 2). Wir schreiben:
   -  46 -                     Kapitel 5: Felder                      -  46 -
 
           INTEGER T(6,4,1986:1987)
   Dies bedeutet, daß jeder 3. Index von 1986 an bis 1987 laufen kann.
   Dieselbe Schreibweise auf die ersten beiden Indizes angewandt ergibt:
           INTEGER T(1:6,1:4,1986:1987)
   was in diesen Fällen aber nur eine ausführlichere Schreibweise ist.
 
      Allgemeine Form der Dimensionierung:
       ________________________________________________________________
      | 1 Dimension:                                                   |
      |       Typ Feldname( Dimensionsangabe )                         |
      | 2 Dimensionen:                                                 |
      |       Typ Feldname( Dimensionsangabe,Dimensionsangabe )        |
      | usw. bis 7 Dimensionen. Dabei ist                              |
      | Typ  -      evtl. mit Länge,  also z.B. REAL oder REAL*8 usw.  |
      | Dimensionsangabe - Anzahl der Elemente                         |
      |                    oder kleinster Index : größter Index        |
      | Im 1. Fall heißen die Feldelemente eines Feldes F              |
      |       F(1) F(2) ... F(Dimensionsangabe)                        |
      | im 2. F(kleinster Ind.) F(kleinster Ind.+1) ... F(größter Ind.)|
      |________________________________________________________________|
 
           Zuweisen von Anfangswerten
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Startwerte für Variable, mit denen das Programm beginnen soll, können
   mit der DATA-Anweisung zugewiesen werden. Beispiele:
           DATA I/4/,A/3./
   Besonders bequem ist dies für Felder, da nicht jeder einzelne Wert
   aufgezählt werden muß. Soll ein Feld anfangs lauter Nullen erhalten,
   so genügt
        REAL F(100), Tabelle(100,100)
        DATA F /100*0./, Tabelle /10000*0./
   Man beachte, daß zuerst im Programm die Typ-Deklarationen REAL,
   INTEGER usw. stehen müssen, falls vorhanden, und erst danach DATA.
   Der Typ der Anfangswerte muß mit dem Typ der entspr. Variablen
   übereinstimmen, ebenso muß die Zahl der angegebenen Anfangswerte
   genau gleich der Zahl der dimensionierten Feldelemente sein, dh.
   ein Feld muß vollständig mit Anfangswerten versorgt werden.
 
           Zusammenfassung
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   1. Oft müssen wir Programme schreiben, in denen wir nicht von
      vornherein wissen, wieviele Variable wir brauchen.
   2. Dieses Problem löst man mit der Deklaration von Feldern (Typ REAL,
      INTEGER, CHARACTER usw.). Feldelemente haben dynamisch veränderliche
      Namen, d.h. die Bezeichnung des Feldelements ändert sich, wenn der
      Index einen neuen Wert annimmt - aus X(i) wird z.B. X(1), X(2),
      X(3)..., wenn i die Werte 1,2,3... annimmt. Auf diese Weise
      können bel. viele Variable angesprochen werden.
   3. Eindimensionale Felder denkt man sich in einer einfachen Liste
      angeordnet (Vektor), zweidimensionale in einer rechteckigen Tabelle.
   4. Es genügt, die Zahl der Feldelemente als Dimensionierung anzugeben;
      die Numerierung läuft dann ab 1 bis zum Endwert. Oder man gibt
      Index-Untergrenze : Index-Obergrenze an, dabei sind negative Zahlen
      und Null möglich; die Numerierung geht ab Untergrenze bis Obergrenze.
   5. Implizite DO-Schleifen erleichtern die Ein/Ausgabe von Feldern.
   6. Anfangswerte für alle Variablen mit der DATA-Anweisung, für Felder
      besonders bequem mit dem Wiederholungsfaktor.
   7. Die Dimensionierung von Feldern kann auch mit Variablen, statt Kon-
      stanten, als Indexgrenzen vorgenommen werden; dies ist jedoch nur in
      Unterprogrammen möglich und wird deshalb erst in Kap. 6 beschrieben.
 
 
 
   -  47 -                     Kapitel 5: Felder                      -  47 -
 
           Aufgaben
           ¯¯¯¯¯¯¯¯
   1. Lesen Sie 5 INTEGER-Variable aus einer Zeile und speichern Sie sie
      im Feld K. Auf 4 Zeilen drucken Sie die Werte, die Indizes der
      Werte, die positiv sind, die negativ sind, die Null sind.
   2. Lesen Sie ein Feld mit 10 INTEGER-Werten ein. Drucken Sie alle Paare
      der Werte des Feldes aus, die als Summe 12 ergeben.
   3. Lesen Sie ein Feld von 10 INTEGER-Werten, die das Alter von 10
      Personen bedeuten sollen. Bestimmen Sie die beiden Personen, die im
      Alter am nächsten sind und die, die am weitesten entfernt sind.
   4. A und B seien je INTEGER(8); lesen Sie die Werte mit impl. DOs ein.
      Drucken Sie die Werte, die je beidesmal in A und B sind; die in B,
      aber nicht in A sind; die in A, aber nicht in B sind; die entweder
      in A oder in B, aber nicht in beiden sind. Testen Sie mit
         A=(2 5 8 4 7 1 6 10)
         B=(9 8 4 10 3 5 12 11)
   5. Erweitern Sie Aufg. 8 von Kap. 4 bzw. Beispiel 5.2 so, daß die
      Quotienten ebenfalls in einem Feld gespeichert werden; man drucke
      in 2 Kolonnen nebeneinander FiboZahl(i+1) / FiboZahl(i) und
      FiboZahl(i) / FiboZahl(i-1). Was fällt dabei ins Auge?
   6. Lesen Sie 4 Zeilen ein, die je 7 INTEGER-Werte für die täglichen
      Temperaturen enthalten; berechnen Sie die durchschnittliche Tempera-
      tur, das Maximum, Mimimum pro Woche. Dasselbe für alle 4 Wochen.
      Die Ergebnisse sollen in einer Tabelle so aussehen:
 
                       Durch.  Max   Min
      Woche1               x     x     x
      Woche2               x     x     x
      Woche3               x     x     x
      Woche4               x     x     x
                         ---------------
      4-Wochen-Statistik   x     x     x
 
   7. Fügen Sie Anweisungen hinzu, sodaß Durchschnitt, Maximum und
      Minimum für jeden Wochentag berechnet werden. Drucken Sie die
      Ergebnisse in einer Tabelle aus.
   8. Die folgende Aufgabe ist eher für Numeriker gedacht:
      Die Ackermann-Funktion A(i,j) ist wie folgt definiert:
          A(0,j) = j+1
          A(i,0) = A(i-1,1)
          A(i,j) = A(i-1,A(i,j-1))
      Sie dient zum Testen von rekursiven Funktionsaufrufen.
      Schreiben Sie ein Programm, das die Werte von A(0,0) bis A(10,10)
      in einer 11 mal 11 -Matrix speichert. Das Element der Zeile i
      Spalte j soll den Wert von A(i,j)) erhalten.
      Die 11 mal 11 - Matrix ist dann mit A(0:10,0:10) zu dimensionieren.
      Man beachte, daß mit diesem Verfahren anstelle des Funktionswertes
      an der Stelle i,j das Matrix-Element mit dem Index (i,j) tritt,
      also gar keine Funktion, sondern ein Matrixelement berechnet wird.
      Schwieriger ist nur herauszufinden, in welcher Reihenfolge die
      Berechnung erfolgen muß, damit sich alle  Elemente der Reihe nach
      aus bereits berechneten Elementen ergeben und nicht irgendwann
      ein noch unbekanntes Element herangezogen wird (was beim rekursiven
      Funktionsaufruf ja gerade gemacht werden darf und soll).
      Tip: Die 11x11-Matrix läßt sich so nicht vollständig berechnen,
        allenfalls die linke obere Dreiecksmatrix einschl. Nebendiagonale
        (von links unten nach rechts oben), also   ( .... )
                                                   ( ...  )
                                                   ( ..   )
        am Beispiel einer 4x4-Matrix gezeigt.      ( .    )
 
 
 
   -  48 -                     Kapitel 5: Felder                      -  48 -
 
           Noch einmal: Schleifensteuerung; der Typ LOGICAL
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Im Kap. 4 hatten wir bereits besprochen, wie mehrere Endebedingungen in
   einer Schleife geschrieben werden. Hier soll das Problem an Hand eines
   Beispiels mit einem Feld noch einmal systematisch vorgeführt werden.
 
   Beispiel 5.5: Suchen in einer Liste
   ¯¯¯¯¯¯¯¯¯¯¯¯
         PROGRAM P55A
   * Ein bestimmter Name soll in einer vorgegebenen Liste gesucht werden
         CHARACTER*5 Liste(10), Name
         DO i=1,10
           IF (Name.EQ.Liste(i)) ???          gefunden! was nun?
         ENDDO                                wenn i > 10, geht es mit der
         PRINT*,'nichts gefunden'             folgenden Zeile weiter
         END
 
   Was soll an der Stelle ??? passieren? Dazu die folgenden Überlegungen:
 
   Der Ausgang über ENDDO wird auch "regulärer" Ausgang der Schleife
   genannt: die Schleife wurde solange durchlaufen, bis die eingebaute
   Logik "beende die Schleife, sobald i > 10" zum Tragen kommt. Dies ist
   der Fall, wenn die Liste erfolglos bis Ende durchsucht wurde.
 
   Ein 2. Ausgang aus der Schleife, wenn nämlich etwas gefunden wurde,
   darf aber nicht auch zu der auf ENDDO folgenden Zeile führen, da dort
   die Meldung "nicht gefunden" steht, sondern zu einer weiter unten
   stehenden Zeile. Zur Lösung des Problems verwenden wird die
 
   Methode: strukturiert mit Einbau einer logischen Variablen,
            QUIT verläßt die Schleife, es geht weiter hinter ENDDO
 
   Zunächst: Der Typ LOGICAL deklariert eine Variable, die nur die Werte
   .TRUE. (wahr) oder .FALSE. (falsch) annehmen kann. Man kann sich so
   z.B. das Ergebnis eines Vergleichs merken. Beispiel s.u.
 
         PROGRAM P55B
   * Ein bestimmter Name soll in einer vorgegebenen Liste gesucht werden
         CHARACTER*5 Liste(10), Name
         LOGICAL gefunden
         DO i=1,10
          gefunden = Name .EQ. Liste(i)
          IF(gefunden) QUIT
         ENDDO
         IF (.NOT. gefunden) THEN
          PRINT*,'nichts gefunden'
         ELSE
          PRINT*,'gefunden als Nr.',i
         ENDIF
         END
 
   Ein weiterer Vorzug der strukturierten Methode ist, daß die Einführung
   der logischen Variablen, die das Ergebnis des Suchvorgangs speichert,
   es möglich macht, an einer späteren Stelle die Information "gefunden"
   oder "nicht gefunden" weiterzuverwenden. Der Ablauf eines strukturier-
   ten Programms dokumentiert sich also automatisch selbst.
 
   Die QUIT-Anweisung ist ein Vorgriff auf den Fortran90-Standard
   (dort heißt es EXIT mit derselben Logik).
 
   Wir wollen das ganze zu einem sinnvollen Programm ausgestalten:
 
 
   -  49 -                     Kapitel 5: Felder                      -  49 -
 
   Aufgabe: Es sei ein Feld von 10 Namen vorhanden. Es soll ein bel. Name
            am Schirm eingelesen werden; das Programm soll die Meldung
            ausgeben, ob der Name in der Liste vorhanden ist oder nicht.
            Das ganze soll in einer Schleife bis zu 20 Mal laufen.
            Vorzeitiges Ende, wenn der Name nur ein Leerzeichen ist.
 
   Algorithmus:
 
   1. Deklariere ein Feld mit 10 Elementen und einen extra Namen
   2. Gib die 10 Namen vor
   3.0 Setze eine Schleife für 20 Durchgänge an
   3.1 Fordere zur Eingabe eines Namens auf
   3.2 Lies den neuen Namen
   3.3 Test auf vorzeitiges Ende
   3.4.0 Setze eine Schleife zum Durchsuchen des Feldes auf
   3.4.2 Vergleiche den neuen Namen mit dem entspr. Element der Liste
   3.4.3 Falls gefunden, in der logischen Variablen "gefunden" vermerken
   3.4.4 Verlassen der Schleife, falls "gefunden"
   3.5. Je nach "gefunden" Meldung, daß Name gefunden / nicht gefunden
   4. Programmende
 
   Fortranprogramm:
 
         PROGRAM P55
         LOGICAL gefunden
         CHARACTER *5 LISTE(10), NAME*5
         DATA LISTE /'Adam','Berta','Cecil','Denis','Emil','Fritz',
        &            'Georg','Hans','Ida','Jo'/
   * das Folgende bis zu 20 Mal:
         DO i=1,20
           PRINT*,'Bitte Namen angeben in ''.....'' max. 5 Buchst.'
           PRINT*,'  '' '' beendet das Programm'
           READ*,Name
           IF (Name .EQ. ' ') THEN
             PRINT*,'Du hast jetzt schon genug? wenn es sein muß...'
             STOP
           ENDIF
   * Suchvorgang
           gefunden = .false.
           DO j=1,10
             gefunden = Name .EQ. Liste(j)
             IF(gefunden) QUIT
           ENDDO
   * Ende der Suche; Ergebnis?
           IF (gefunden) THEN
             PRINT*,'gefunden als Nr.',j
           ELSE
             PRINT*,'nichts gefunden'
           ENDIF
         ENDDO
         PRINT*,'Du kannst ja nie genug bekommen...'
         END
 
   Kommentar zu der Zeile "gefunden = Name .EQ. Liste(j)" :
 
   Die logische Variable gefunden bekommt den Wahrheitswert des Vergleichs
   Name .EQ. Liste(j)
   Dies ist eine elegante Schreibweise für das umständliche
         IF ( Name .EQ. Liste(j) THEN
            gefunden = .TRUE.
         ELSE
            gefunden = .FALSE.
         ENDIF
   -  50 -                 Kapitel 6: Unterprogramme                  -  50 -
 
 
                           Kapitel 6: Unterprogramme
                           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
           Fragen
 
   1. Welche Vorteile bringt das Schreiben von Fortranprogrammen
      in einzelnen separaten Teilen (Programm-Einheiten) ?
   2. Wann werden allgemeine wann Unterprogramme (SUBROUTINE-Anweisung),
      wann Funktionen (FUNCTION-Anweisung) verwendet?
   3. Was versteht man unter einer modularen Programmiersprache?
 
           Programmeinheiten
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Bisher hatte unser Fortran-Programm folgende Form:
      1.        PROGRAM name
      2.           Deklarationen (Typen, Felder, DATA)
      3.           Anweisungen
      4.        END
 
   Dies nennt man eine Programmeinheit; das Fortran-Programm bestand
   also bisher nur aus dem Hauptprogramm.
   Vom Hauptprogramm aus können weitere Unterprogramme aufgerufen werden;
   jedes Unterprogramm bildet wieder eine Programmeinheit; deren Form ist
   (da es 2 Sorten von Fortran-Unterprogrammen gibt):
 
      1.  SUBROUTINE name ( Parameter-Liste )   bzw.  FUNCTION name ( .. )
      2.    Deklarationen (Typen, Felder, DATA)
      3.    Anweisungen
      4.  END
 
   also bis auf den Kopf des Unterprogramms dieselbe Struktur wie das
   Hauptprogramm; wichtig ist aber, daß die END-Anweisung im Unterprogramm
   zwar dieses beendet, man aber anschließend wieder ins Hauptprogramm
   zurückkehrt, nämlich hinter die Stelle des Aufrufs. Ein Unterprogramm
   kann auch ein zweites aufrufen usw. (aber nicht rekursiv), sodaß die
   Rückkehr dann jeweils ins übergeordnete (rufende) Programm geschieht.
 
   Der Aufruf einer selbst geschriebenen Funktion geschieht wie der Aufruf
   einer eingebauten: durch den Funktionsnamen, dem in Klammern die
   Argumenten-Liste folgt. Der Funktionsname wird durch den berechneten
   Wert ersetzt und die Auswertung des Ausdrucks fortgesetzt.
 
   Der Aufruf einer Subroutine geschieht mit der Anweisung
           CALL name ( Argumenten-Liste )
   Die Argumente werden den Parametern zugeordnet, d.h. deren Werte sind
   unter den Namen der Parameter verfügbar (s.u.).
 
           Subroutine-Unterprogramme
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Beispiel 6.1:
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Die Fakultät von n soll als Unterprogramm (Subroutine) mit dem Namen
   Fak geschrieben werden:
 
        SUBROUTINE Fak(n,Fakn)
        INTEGER n,Fakn,i
        Fakn=1
        IF (n.GT.1) THEN
          DO i=2,n
            Fakn = Fakn * i
          ENDDO
        ENDIF
        END
   -  51 -                 Kapitel 6: Unterprogramme                  -  51 -
 
   Die 1. Zeile enthält 3 Informationen:
   1. Art des Unterprogramms (SUBROUTINE)
   2. Name des Unterprogramms (FAK)
   3. Parameter des Unterprogramms (N,FAKN)
 
   Wir benutzen dies, um "k über l" zu berechnen nach der Formel
   k über l  =  k! / ( l! * (k-l)! )       (! bezeichnet die Fakultät)
 
   Beispiel 6.2: K über L
   ¯¯¯¯¯¯¯¯¯¯¯¯
        PROGRAM P62
        INTEGER k,l, fakk, fakl, fakk_l
        READ*, k,l
        CALL FAK( k, fakk)
        CALL FAK( l, fakl)
        CALL FAK( k-l, fakk_l)
        PRINT*, k ' über',l, ' =', fakk / (fakl * fakk_l)
        END
 
   Anmerkungen:
   1. Der Aufruf einer Subroutine erfolgt mit der CALL-Anweisung:
      "CALL", dann den Namen des Unterprogramms, dann die Argumente.
   2. Argument kann eine Konstante, ein Ausdruck oder eine Variable sein.
      Sie liefern Werte an die Parameter der Subroutine. Variable können
      neue Werte durch die Subroutine bekommen und diese zurückgeben.
   3. Die Zuweisung eines Wertes an einen Parameter in der Subroutine, wo
      das entspr. Argument eine Konstante oder ein Ausdruck war, führt zu
      einem *ERR*. Variablen-Argumente dürfen (z.B. durch Zuweisung) im
      Unterprogramm verändert werden. Dies muß beim Aufruf beachtet werden.
   4. Die END-Anweisung beendet das Unterprogramm, schreibt die evtl. ver-
      änderten Werte der Parameter an die Argumente zurück und kehrt ins
      rufende Programm zurück. Dies ist auch durch die RETURN-Anweisung
      an bel. Stelle des Unterprogramms möglich (analog der STOP-Anweisung
      im Hauptprogramm).
   5. Ein Fortran-Programm kann also aus dem Hauptprogramm (gekennzeichnet
      durch die PROGRAM-Anweisung) und mehreren Unterprogrammen bestehen.
      Jede solche Programmeinheit wird mit END abgeschlossen.
      Die Reihenfolge ist nicht vorgeschrieben.
 
   Beispiel 6.3:
   ¯¯¯¯¯¯¯¯¯¯¯¯
        SUBROUTINE SUB(a,b)
        a=a+b
        END
   *
        PROGRAM AplusB
        x=1.
        y=1.
        DO i=1,5
          CALL SUB(x,y)
          PRINT*,x
        ENDDO
        PRINT*,y
        END
   Der Wert von y bleibt gleich, weil der Parameter b sich nicht ändert;
   der Wert von x erhöht sich jeweils um 1. (den Wert von y).
 
   Beispiel 6.4:
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Wir schreiben eine Subroutine, um in einem Feld von 10 INTEGERs
   die Nummer des kleinsten Elements zu bestimmen.
   Der Algorithmus nimmt das 1. Element und vergleicht dies mit dem
   folgenden; ist dies kleiner, wird dieses weiterverwendet.
   -  52 -                 Kapitel 6: Unterprogramme                  -  52 -
 
        SUBROUTINE KLEINSTES (Feld, Nummer)
        INTEGER Feld(1:10), Test, i
        Nummer = 1
        Test = Feld(Nummer)
        DO i=2,10
          IF (Feld(i) .LT. Feld(Nummer) THEN
            Test =(Feld(i)
            Nummer = i
          ENDIF
        ENDDO
        END
 
   Beispiel 6.5: Sortierprogramm
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Algorithmus:
   1. Wir lesen die 10 Werte in des Feld ein
   2. führe folgendes 10 mal aus:
   2.1 finde das kleinste Element und drucke es
   2.2 sorge dafür, daß dieses Element nie wieder das kleinste wird
   3. Ende
 
        PROGRAM P65
   * Sortierprogramm, benötigt die Subroutine KLEINSTES oben
        INTEGER F(10),i,n
        READ*, F
        DO i=1,10
           CALL KLEINSTES ( F, n )
           PRINT*, F(n)
           F(n) = 999999
        ENDDO
        END
 
    Anmerkungen:
    1. Der Name des Feldes wird mit CALL als Argument übergeben.
    2. Das Feld muß in der Subroutine dimensioniert werden.
    3. Der Typ entsprechender Felder muß gleich sein (beide INTEGER),
       die Anzahl der Elemente (Dimensionierung) ist hier ebenfalls
       gleich, sie darf im Unterprogramm jedenfalls nicht größer sein
       als im rufenden Programm).
 
   Beispiel 6.6: Quadratische Gleichung
   ¯¯¯¯¯¯¯¯¯¯¯¯
                                                2
   Wir lösen die allg. quadratische Gleichung ax +bx+c; die Koeffizienten
   sollen am Schirm eingegeben werden:
 
         PROGRAM P66
   * Quadratische_Gleichung
         REAL  a,b,c, n1,n2
         DO i=1,10
           READ*,a,b,c
           IF ( a .EQ. 0.0 ) STOP
           CALL QUAD(a,b,c,n1,n2)
           WRITE(6,100)  '1. Nullstelle:',n1,' 2.Nullstelle:',n2
         ENDDO
   100   FORMAT(1X,A,G14.7,A,G14.7)
         END
 
 
 
 
 
 
   -  53 -                 Kapitel 6: Unterprogramme                  -  53 -
 
         SUBROUTINE QUAD(x,y,z,Erste,Zweite)
         Real  x,y,z, Erste,Zweite, Diskr
         Diskr = y*y - 4.0*x*z
         IF ( Diskr .LT. 0 ) THEN
           PRINT*,' Gleichung hat keine reellen Nullstellen'
         ELSE
           Erste  = (-y +SQRT(Diskr) ) /(2.0*x)
           Zweite = (-y -SQRT(Diskr) ) /(2.0*x)
         ENDIF
         END
 
   Bemerkungen:
   1. Das Programm wiederholt sich, bis max. 10 verschiedenen Gleichungen
      bearbeitet sind: DO i=1,10
   2. Sobald für a eine 0 eingetippt wird: STOP wegen "IF(a.EQ.0) STOP";
      b und c müssen aber trotzdem beachtet werden, z.B. als  "0/" .
 
           Übungen
           ¯¯¯¯¯¯¯
   1. Beispiel 6.6 hat einen Schönheitsfehler:
      Falls die Nullstellen nicht reell sind, wird dies zwar angemerkt,
      jedoch werden (falsche) Werte angegeben. Verbessern Sie dies im
      Programm. Frage: welche  Werte werden zu Unrecht ausgegeben?
   2. Beschreiben Sie die Ausgabe der Paare Hauptprogramm/Subroutine.
      Geben Sie jeweils 3 Punkte an:
      1) Anzahl und Typ der einzelnen Argumente (Parameter)
      2) welche Werte hineingehen, welche herauskommen (Ergebnisse)
      3) was die Ergebnisse aus den eingehenden Werten machen
      NB: Das Wie (der Algorithmus) interessiert an dieser Stelle nicht!
 
    a) PROGRAM A                   SUBROUTINE FCN(K,L)
         I=1                         L=K**2-3*K+5
         CALL FCN(I,J)             END
         PRINT*,I,J
       END
    b) PROGRAM B                   SUBROUTINE ADD(TAB)
         REAL AB(10)/10*1./          REAL TAB(10)
         DO N=1,4                   DO I=2,6,2
            CALL ADD(AB)               TAB(I-1)=TAB(I-1)-1
         ENDDO                         TAB(I)=TAB(I)+1
         PRINT*,AB                   ENDDO
       END                         END
    c) PROGRAM C                   SUBROUTINE R(J,N)
         M=0
         DO J=1,4                   DO K=1,J
            CALL R(J,M)                N=N+K
         ENDDO                       ENDDO
         PRINT*,M
       END                         END
    d) PROGRAM D                   SUBROUTINE HELP(K,L)
         INTEGER L/1/,K/2/           INTEGER KL/5/
         CALL HELP(I,K)              KL=KL*K/L
         CALL HELP(K,L)              K=KL*L
         PRINT*,L,K
       END                         END
       Hinweis: beim 2. Aufruf von HELP hat KL nicht den Wert 5!
    e) PROGRAM E                   SUBROUTINE SUB
         KA=1                        INTEGER N/1/
     3   CALL SUB                    IF (N.GT.10) STOP
         KA=KA+1                     N=N+1
         GOTO 3
       END                         END
 
   -  54 -                 Kapitel 6: Unterprogramme                  -  54 -
 
   3. Wo liegt der Fehler?
 
     a) CALL SUB(X,Y)              SUBROUTINE SUB(Z)
     b) INTEGER MAX(1)
        CALL SUB(MAX,A)            SUBROUTINE SUB(J,R)
     c) REAL A(10),J0              SUBROUTINE SUB(B,ZY)
        CALL SUB(J0,A)             REAL B(100)
     d) CALL SUB(3)                SUBROUTINE SUB(OH)
     e) CALL (A,B,C,D,E)           SUBROUTINE (W,X,Y,Z,E)
     f) CALL SUB(MAT(10),F)        SUBROUTINE SUB(MAT(10),F)
     g) CALL SUB(5.3)              SUBROUTINE SUB(S)
                                   REAL S(1)
     h) X=SUB(Y)                   SUBROUTINE SUB(Y)
     i) CALL SUB(A)                SUBROUTINE SUB(1.375)
     j) ABC=5.                     SUBROUTINE SUB(RST,XYZ)
        CALL SUB(ABC,DEF)          RST=RST+XYZ
        END                        END
     k) X=2.                       SUBROUTINE SUB(X,Y,Z)
        Y=2.                       Z=X**Y
        CALL SUB(X,Y,Z)            END
        END
 
          Function-Unterprogramme
          ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Die 2. Art von Unterprogrammen ist die Funktion (FUNCTION). Sie bringt
   mit dem Funktionsnamen den Funktionswert zurück. Daher die Regel:
      In Funktionen sollen die Parameter niemals Werte zurückbringen!
   Oder anders ausgedrückt: Funktionen sollen unter keinen Umständen ihre
   Parameter (und damit die entspr. Argumente) verändern.
   Wenn dies erforderlich ist, verwende man eine Subroutine.
 
   Beispiel 6.7: Fakultät als Function:
   ¯¯¯¯¯¯¯¯¯¯¯¯
         INTEGER FUNCTION Fak(n)
         Fak=1
         IF (n.GT.1) THEN
           DO i=2,n
             Fak = Fak * i
           ENDDO
         ENDIF
         END
 
   Anmerkung:
   Es gelten dieselben Regeln wie bei der Subroutine. Zusätzlich:
   1. Vor "FUNCTION" kann der Typ des Funktionswertes angegeben werden
      (falls nicht nach der "1. Buchstaben Regel").
   2. Der Funktionswert wird dem Namen der Funktion wie einer Variablen
      in der Function zugewiesen.
   3. Der Funktionsaufruf geschieht innerhalb eines Ausdrucks.
 
   Beispiel 6.8: K über L Version 2
   ¯¯¯¯¯¯¯¯¯¯¯¯
   PROGRAM P68
   * benötigt die Function Fak oben
         INTEGER k,l, Fakk, Fakl, Fakk_l ,Fak
         READ*, k,l
         Fakk = Fak(k)
         Fakl = Fak(l)
         Fakk_l = Fak( k-l )
         PRINT*, k ' über',l, ' =', Fakk / (Fakl * Fakk_l)
         END
   NB: Fak als INTEGER FUNCTION muß als INTEGER deklariert werden, da
       sonst nach der 1. Buchstaben Regel in P68 Fak REAL wäre!
   -  55 -                 Kapitel 6: Unterprogramme                  -  55 -
 
   Beispiel 6.9: K über L Version 3
   ¯¯¯¯¯¯¯¯¯¯¯¯
   wie P68, aber kürzer:
 
         PROGRAM P69
         INTEGER Fak
         READ*, k,l
         PRINT*, k ' über',l, ' =', Fak(k) / (Fak(l) * Fak(k-l) )
         END
 
   Übung
   ¯¯¯¯¯
   Schreiben Sie das obige Sortierprogramm um, indem Sie statt einer
   Subroutine eine FUNCTION KLEINSTES benutzen.
 
   Ein weiteres Beispiel
   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Beispiel 6.10
   ¯¯¯¯¯¯¯¯¯¯¯¯¯
   Aufgabenstellung:
 
   Man lese 3 Zahlen ein; sie sollen die Längen der 3 Seiten eine
   Dreiecks sein. Wenn dies überprüft ist, soll herausgefunden werden,
   ob das Dreieck stumpf-, recht- oder spitzwinklig ist.
   Für die Plausibilitätsprüfung müssen wir einmal ausschließen,
   daß einer der 3 Kandidaten für Seitenlängen kleiner 0 ist. Außerdem
   darf eine Seite nicht länger als die Summe der beiden anderen sein.
   Sodann sagt Pythagoras, daß im rechtwinkligen Dreick die Summe der
   Quadrate der beiden kürzeren Seiten gleich dem Quadrat der längeren
   Seite ist. Ist das Quadrat größer als die Summe, ist es ein
   stumpfwinkliges, ist es kleiner, ein spitzwinkliges Dreieck.
 
   Algorithmus:
 
   1. Lies die 3 Werte ein.
   2. Falls einer der 3 Werte < 0
         ist die Funktion Ist_ein_Dreieck FALSE (kein Dreieck)
   2.2 sonst
       falls größte Seite > Summe der anderen
         ist die Funktion Ist_ein_Dreieck FALSE (kein Dreieck)
       sonst
         ist die Funktion Ist_ein_Dreieck TRUE  (Dreieck)
                   in der Form: Ist_ein_Dreieck bekommt den Wahrheitswert
                      des Vergleichs "größte Seite > Summe der anderen"
      Zur Bestimmung der größeren Seite verwenden wir die Funktion MAX.
      Falls also ein Dreieck möglich ist, testen wir den Typ des Dreiecks:
   3. Bestimme die längste und die kürzeren Seiten.
   4. Berechne den Wert
      längste Seite ** 2  - ( mittlere ** 2 + kleinere ** 2 )
   5. Falls der Wert
         < 0 : Typ ist spitzwinklig
         = 0 : Typ ist rechtwinklig
         > 0 : Typ ist stumpfwinklig
 
   Wir wollen also die folgenden Funktionen verwenden:
 
         LOGICAL FUNCTION Ist_ein_Dreieck(s1,s2,s3)
   mit der Bedeutung TRUE: ist ein Dreieck; FALSE: ist kein Dreieck.
   Parameter sind die 3 Seitenlängen
 
         INTEGER FUNCTION Typ_des_Dreiecks(s1,s2,s3)
   s1,s2,s3 wie oben; die Zahlen 1,2,3 sollen den Typ des Dreiecks angeben
   mit der Bedeutung 1=spitzwinklig, 2=rechtwinklig, 3=stumpfwinklig.
   -  56 -                 Kapitel 6: Unterprogramme                  -  56 -
 
         PROGRAM P6_10
   * liest 3 Zahlen (Längen) und bestimmt, ob überhaupt ein Dreieck
   * vorliegt; wenn ja, wird der Typ des Dreiecks bestimmt
         INTEGER spitzwinklig, rechtwinklig, stumpfwinklig
         PARAMETER ( spitzwinklig=1, rechtwinklig=2, stumpfwinklig=3 )
         REAL      Seite1, Seite2, Seite3
         LOGICAL   Ist_ein_Dreieck
         INTEGER   Typ_des_Dreiecks
   * es folgen die ausführbaren Anweisungen
         WHILE( .TRUE. )
         PRINT*,'Bitte die 3 Seiten eingeben; Strg_z endet!'
         READ(*,*,END=99) Seite1,Seite2,Seite3
         PRINT*,'Die Längen sind:'
         PRINT*,Seite1,Seite2,Seite3
         IF( Ist_ein_Dreieck(Seite1,Seite2,Seite3) )THEN
            PRINT*, '    Das Dreieck ist '
            SELECT( Typ_des_Dreiecks ( Seite1,Seite2,Seite3 ) )FROM
              CASE spitzwinklig
                   PRINT*,'    spitzwinklig'
              CASE rechtwinklig
                   PRINT*,'    rechtwinklig'
              CASE stumpfwinklig
                   PRINT*,'    stumpfwinklig'
            ENDSELECT
         ELSE
            PRINT*,'   Das gibt kein Dreieck'
         ENDIF
         ENDWHILE
     99  PRINT*,'Programmende'
         END
    *
         LOGICAL FUNCTION Ist_ein_Dreieck( s1,s2,s3 )
         REAL  s1, s2, s3, Laengste_Seite
         IF ( s1 .LE. 0  .OR.  s2 .LE. 0  .OR.  s3 .LE. 0 ) THEN
              Ist_ein_Dreieck = .FALSE.
         ELSE
              Laengste_Seite = MAX( s1, s2, s3)
              Ist_ein_Dreieck = Laengste_Seite .LT. 0.5 * (s1 + s2 + s3)
    *         je nachdem wird Ist_ein_Dreieck TRUE oder FALSE
         ENDIF
         END
    *
         INTEGER FUNCTION Typ_des_Dreiecks(s1,s2,s3 )
         INTEGER spitzwinklig, rechtwinklig, stumpfwinklig
         PARAMETER ( spitzwinklig=1, rechtwinklig=2, stumpfwinklig=3 )
         REAL      s1,s2,s3   ,wenig
         PARAMETER ( wenig = 0.000001 )
         REAL      lang, mittel, kurz, Differenz
         lang   = MAX (S1, S2, S3)
         kurz   = MIN (S1, S2, S3)
         mittel = S1 + S2 + S3 - ( lang + kurz )
         Differenz = lang**2 - ( mittel**2 + kurz**2 )
         IF( ABS(Differenz) .LT. wenig )THEN
             Typ_des_Dreiecks = rechtwinklig
         ELSEIF( Differenz .GT. 0 )THEN
             Typ_des_Dreiecks = stumpfwinklig
         ELSE
             Typ_des_Dreiecks = spitzwinklig
         ENDIF
         END
 
 
 
   -  57 -                 Kapitel 6: Unterprogramme                  -  57 -
 
    Als Dateneingabe nehmen Sie z.B.
     3  4  5
     3  4  6
     3  4  4
     3  4 10
     3  4 -1
     0  1  1
   und dann Strg_z (am PC)
 
   Kommentar:
   1. Die PARAMETER-Anweisung gibt den in der Klammer angegebenen
      Namen festen Werte. Man nennt dies "Deklaration von Konstanten".
   2. Die Schleife WHILE(.TRUE.) ... ENDWHILE ist eine Endlosschleife.
      Sie wird nur über die Aktivierung von "END=99" verlassen.
   3. Die SELECT-Anweisung SELECT( integer-wert )FROM
                            CASE integer-wert   oder von:bis oder ..,..,..
                           ENDSELECT
      stellt einen Vorgriff auf den Fortran90-Standard dar (dort heißt es
      SELECT CASE(integer-wert) ... ENDSELECT
      So können in Abhängigkeit des INTEGER-Wertes eine Liste von Aktionen
      ausgeführt werden. Ohne diese Anweisung müßte man schreiben:
      IF(     integer-wert .EQ. 1) THEN ...
      ELSEIF( integer-wert .EQ. 2) THEN ...
      ELSEIF( integer-wert .EQ. 3) THEN ...
      ENDIF
 
           Module, Programmbibliotheken
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Ein Modul ist eine Unterprogrammeinheit, die mindestens die folgende
   Eigenschaft aufweist:
 
      Eine modulare Unterprogrammeinheit bekommt ihre Information von der
      rufenden Programmeinheit nur über die Parameter-Liste;
      sie liefert Information nur über diese (bei Funktionen
      über den Funktionsnamen) an das rufende Programm zurück
 
   Daraus ergibt sich als Konsequenz:
   1. Die Namensgebung der Variablen, Felder usw. ist für jede modulare
      Programmeinheit beliebig; der Programmierer muß nur die Übersicht
      über die Namen der laufenden Programmeinheit behalten.
      Diese Größen nennt man "lokal", s.u. "Gültigkeitsbereich von Namen".
   2. Unterprogramme können von verschiedenen Programmierern geschrieben
      werden, wenn eine Übereinkunft über die Art der Parameter (und damit
      der Argumente) besteht: die "Schnittstelle" zwischen den Moduln
      muß bekannt sein ("öffentlicher" Teil des Unterprogramms); alles
      andere, also auch die Methode ("privater" Teil des Unterprogramms),
      kann dem rufenden Programm, kann dem Anwender unbekannt bleiben.
   3. In Fortran wurde damit das Bibliothekskonzept verwirklicht: man
      kann selbst geschriebene oder von anderen erstellte Unterprogramme
      (Unterprogrammbibliotheken) benutzen, aus denen der Fortran-Compiler
      automatisch die jeweils benötigten (aufgerufenen) Unterprogramme
      (Subroutine oder Function) auswählt und zum Laufen bringt.
 
           Aufgaben
           ¯¯¯¯¯¯¯¯
   1. Schreiben Sie eine Subroutine, deren Parameter ein Vektor mit 10
      INTEGERs ist. Das Unterprogramm soll die 10 Werte in umgekehrter
      Reihenfolge zurückgeben.
   2. Schreiben Sie eine Function DET, die die Determinante einer 2x2-
      Matrix zurückgeben soll. Die Function soll als Parameter den Namen
      der Matrix haben. (Formel: falls die 4 Matrixelemente a,b,c,d sind,
      ist deren Determinante = a*c - b*d )
 
   -  58 -                 Kapitel 6: Unterprogramme                  -  58 -
 
   3. Schreiben Sie eine Subroutine zur Lösung von 2 linearen Gleichungen
      mit 2 Unbekannten nach der Cramerschen Regel. Die Subroutine soll
      folgende Parameter haben: KOEFF (2x2-Matrix der Koeffizienten),
      RS (Vektor der rechten Seite), LOESUNG (Vektor der Lösungen),
      IFLAG bekommt den Wert 0, falls die Gleichungen keine Lösung
      haben, 1 wenn nur 1 Lösung, 2 wenn es unendlich viele Lösungen gibt;
      z.B. für  2x + 3y = 12   ist KOEFF= ( 2. 3.),  RS= (12.)
               -4x + 8y =  4              (-4. 8.)       ( 4.)
      Das Ergebnis wäre dann LOESUNG = (3. 2.) und IFLAG = 1
      Schreiben Sie ein Hauptprogramm, welches diese Werte mit DATA
      bereitstellt, die Subroutine aufruft und IFLAG auswertet.
 
   4. Schreiben Sie eine Subroutine namens RANDI zur Erzeugung von 60
      "Zufalls"-Zahlen INTEGER R(60) im Bereich j bis k. Methode:
      Setze R(1) = eine positive INTEGER-Zahl < 65536. Für N=2,3,...:
      R(n) = MOD(25173*(R(n-1),65536). Dies erzeugt 6 Zahlen im Bereich
      1...65535. Um auf den Bereich j...k zu kommen, ersetze man R(i)
      durch  R(i)/65535.0 *(k-j+1) + j
      Die Parameter von RANDI sind R,J und K.
      Testen Sie Ihr Unterprogramm durch ein Hauptprogramm, welches die
      60 Zufallszahlen in 10 Zeilen zu je 6 Werten ausdruckt.
 
   5. Verwenden Sie RANDI für das folgende Problem:
      Erzeugen Sie 200 Zufallszahlen im Bereich 1...6. Nehmen Sie jeweils
      2 Zahlen zusammen zu einem Wurf zweier Würfel.
      Schreiben Sie ein Programm, welches folgende Frage beantwortet:
      Wie oft traten die 36 möglichen Wurfergebnisse auf?
      Schreiben Sie die Ergebnisse in eine 6x6-Tafel, wo die Zeile den
      Wert des 1. Würfels, die Spalte den des 2. Würfels in jedem Doppel-
      wurf bedeuten. Mit welcher relativen Häufigkeit traten die 11
      möglichen Summen 2,3,...,12 auf? Drucken Sie entsprechende Header,
      gefolgt von 11 Zeilen Statistik.
 
   6. Schreiben Sie eine Subroutine mit den 2 Parametern: K, ein Feld von
      20 INTEGERs, und INSERT. Die Werte von K und von INSERT werden
      an das Unterprogramm übergeben. Der Wert von INSERT soll nicht-
      absteigend (d.h. aufsteigend oder gleichgroß) einsortiert werden.
      Schreiben Sie ein Hauptprogramm,das die 20 Werte auf 0 initialisiert
      und dann 20 mal je 1 Wert einliest und einsortiert. Drucken Sie
      am Ende die 20 Werte aus (sie müssen steigende Werte haben).
 
   7. Schreiben Sie ein Programm, welches das Pascalsche Dreieck max. 10.
      Ordnung ausgibt. Definition der Zeile n im Pascalschen Dreieck:
      ( n )   ( n )         ( n )        ( n )
      ( 0 ) , ( 1 ) , ... , ( n )     wo ( m ) "n über m" bedeuten soll.
      Programmende bei Eingabe einer negativen Ordnung.
      Man verwende folgende Hauptprogrammstruktur:
            INTEGER Zeile(11), ...
            WHILE ( .TRUE. )
               CALL EINGABE ( Ordnung, Max_Ordnung, Ende )
               IF ( Ende ) QUIT
               CALL BERECHNE ( Zeile, Ordnung )
            ENDWHILE
            PRINT*,...
      sowie die folgenden Unterprogramme:
            SUBROUTINE EINGABE ( ... )
            SUBROUTINE BERECHNE ( ... )
      *     ruft UEBER auf
              CALL AUSGABE ( Zeile, Nummer )
            SUBROUTINE AUSGABE ( ... )
            INTEGER FUNCTION UEBER ( a,b )
      *     ruft FAK auf
            INTEGER FUNCTION FAK ( n )
   -  59 -                 Kapitel 6: Unterprogramme                  -  59 -
 
           Dimensionierung zur Ausführungszeit
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   In allen bisherigen Beispielen war die Dimensionierung der Felder im
   Unterprogramm gleich der im übergeordneten Programm. Dies ist jedoch
   nicht erforderlich, wenn man die Regel beachtet, daß keine Dimension
   durch ein Unterprogramm erweitert werden kann. Man erhält damit eine
   Möglichkeit, mit demselben Unterprogramm Vektoren und Matrizen mit
   unterschiedlicher Größe (unterschiedlicher Anzahl der Elemente in
   jeder Dimension) verarbeiten zu können.
 
   Beispiel 6.11
   ¯¯¯¯¯¯¯¯¯¯¯¯¯
      PROGRAM HAUPT           SUBROUTINE SUB(X,N)     SUBROUTINE SUB(X)
      REAL A(20), B(100)      REAL X(n)               REAL X(*)
      CALL SUB(A,20)          DO i=1,n...
      CALL SUB(B,100)            ......
      CALL SUB(B(50),30)            ......
      END                     ENDDO                   ENDDO
                              END                     END
 
   Hier sehen wir, daß dieselbe Aktion von SUB einmal mit den 20 Elementen
   von A und dann mit den 100 Elementen von B durchgeführt wird. Der Wert
   N in der Dimensionierung von X besagt, daß mit X einmal die 20 Elemente
   von A und dann die 100 von B angesprochen werden. Im 3. Fall hat X die
   30 Elemente von B ab dem 50. ( ab B(50)), also B(50),B(51),...B(79).
 
   Es geht jedoch auch kürzer:
        PROGRAM HAUPT           SUBROUTINE SUB(X)
        REAL A(20), B(100)      REAL X(*)
        CALL SUB(A)             DO i=1,n...
        CALL SUB(B)                ......
        CALL SUB(B(50))               ......
        END                     ENDDO
                                END
   Der Stern in der Dimensionierung von SUB übernimmt automatisch die
   Dimensionierung aus dem rufenden Programm.
 
   Beispiel 6.12
   ¯¯¯¯¯¯¯¯¯¯¯¯¯
   Die Matrix (1 4 7) wird bearbeitet (denken Sie daran, daß Fortran
              (2 5 8)
              (3 6 9)
                           eine Matrix spaltenweise mit Werten füllt!)
       PROGRAM merkwuerdig                     SUBROUTINE SUB(X,n,m)
       INTEGER A(1:3,1:3)/1,2,3,4,5,6,7,8,9/   INTEGER X(1:n,1:m)
       CALL SUB(A,2,2)                         PRINT*,X
       END                                     END
 
   N und M sind 2, also ist X(1:2,1:2) dimensioniert. Es sollte also der
   obere linke 2x2-Ausschnitt der Matrix A mit PRINT*,X ausgegeben werden,
   also (1 4) bzw. in der Fortran-Reihenfolge (spaltenweise) die Zahlen
        (2 5)
   in der Reihenfolge 1 2 4 5.
   Das Ergebnis ist aber 1 2 3 4. Warum?
   Die Deklaration A(1:3,1:3) reserviert 9 Speicherplätze für die 9
   Elemente, spaltenweise und hintereinander. X(1:2,1:2) tut dasselbe
   mit 4 Elementen, wobei das 1. Element von X mit dem 1. Element von
   A identisch sind. Wir haben also folgende Sicht der Dinge:
   Das Hauptprogramm sieht den Speicher so:
 
   < Spalte 1 von A >   < Spalte 2 von A >   < Spalte 3 von A >
     1      2      3      4      5      6      7      8      9
     
   -  60 -                 Kapitel 6: Unterprogramme                  -  60 -
 
   Das Unterprogramm sieht den Speicher wie unten   ...
   Wie können wir dann aber die erwünschte 2x2- Teilmatrix von A an das
   Unterprogramm übergeben und ausdrucken? Wir übergeben das Feld A mit
   der Originaldimensionierung und benutzen die beiden Werte 2,2 zur
   Markierung des entspr. Ausschnitts der Matrix:
 
       PROGRAM teilmatrix            SUBROUTINE SUB(X,Norig,Morig,n,m)
       INTEGER A(1:3,1:3)/.../       INTEGER X(Norig,Morig)
       CALL SUB(A,3,3,2,2)           PRINT*, (( X(i,j), i=1,n), j=1,m)
       END                           END
 
   Auch hier können wir die rechts stehende (letzte) Dimensionierung
   mit dem Stern automatisch übernehmen mit INTEGER X(NORIG,*).
   Der Aufruf und die Parameter-Liste von SUB verkürzen sich entsprechend:
       CALL SUB(A,3,2,2)    mit      SUBROUTINE SUB(X,NORIG,N,M)
   Leider funktioniert der Stern nicht mit den weiter vorn stehenden
   Dimensionen, INTEGER X(*,*) ist also nicht möglich.
 
   Beispiel 6.13
   ¯¯¯¯¯¯¯¯¯¯¯¯¯
   Es werden 20 Elemente in ein REAL-Feld eingelesen.
   Es sollen die Durchschnittswerte mit der Function MITTEL berechnet
   werden, und zwar von allen 20, von allen außer dem 1., dem 2. usw.
   bis zum letzten Element.
 
         PROGRAM gleitender_Durchschnitt   REAL FUNCTION Mittel(X,n)
         REAL Val(20),Mittel               REAL X(*)
         READ*,Val                         Mittel = 0.
         DO i=1,20                         DO i=1,n
            PRINT*,Mittel(Val(i),21-i)        Mittel=Mittel+X(i)
         ENDDO                             ENDDO
         END                               Mittel=Mittel/n
                                           END
 
   Der 2. Parameter von MITTEL gibt die Zahl der Elemente von X an, die
   in der DO-Schleife aufaddiert werden sollen. Für I=1 im Hauptprogramm
   sollen alle 20 genommen werden, also steht im Aufruf als 2. Parameter
   21-I. NB: Jeder andere kleinere (positive) Wert wäre auch zulässig.
   Man beachte auch, daß MITTEL im rufenden Programm als REAL deklariert
   werden muß, da sonst die Erste-Buchstaben-Regel MITTEL als INTEGER
   betrachten würde.
 
           Externe Unterprogramme
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Wir wollen ein Unterprogramm schreiben, welches das Minimum einer ganz
   beliebigen Funktion bestimmen soll. Nehmen wir an, wir hätten die
   beiden Funktionen
               FA(i) = (50-i)²/i²      für i=1,2,...,100
               FB(i) = 120 - (i-60)²   für i=1,2,...,100
   und folgendes Programm:
 
   Beispiel 6.14
   ¯¯¯¯¯¯¯¯¯¯¯¯¯
   PROGRAM P6_14                    SUBROUTINE MINI(klein,F)
   EXTERNAL FA,FB                   klein=F(1)
   CALL MINI(m,FA)                  DO i=2,100
   PRINT*,'Minimum von FA ist',m      IF ( F(i) .LT. klein) klein=F(i)
   CALL MINI(m,FB)                  ENDDO
   PRINT*,'Minimum von FB ist',m    END
   END
   FUNCTION FA(j)                   FUNCTION FB(k)
   FA=(50-j)**2/j**2                FB=120-(k-60)**2
   END                              END
   -  61 -                 Kapitel 6: Unterprogramme                  -  61 -
 
   Das 2. Argument von "CALL MINI" übergibt nicht den Wert einer Funktion,
   sondern den Namen, so dieser in einer EXTERNAL-Deklaration des rufenden
   Programms enthalten ist. Das gerufene Unterprogramm hat den Platzhalter
   "F" für den jeweils übergebenen Funktionsnamen bereit und ruft beim
   1. Aufruf FA, beim 2. FB. Selbstverständlich muß dem Unterprogramm MINI
   Typ und Zahl der Argumente der Funktionen bekannt sein: alle mit "F"
   gerufenen Funktionen müssen offenbar dieselbe Parameter-Liste haben
   (Typ und Anzahl), können aber mit beliebigen Werten aufgerufen werden.
 
           Zusammenfassung: Wirkungsweise des Aufrufs
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Wir schreiben:
            CALL abc( Argumenten-Liste )       mit der Subroutine abc:
      SUBROUTINE abc( Parameter-Liste )
   oder
         var = xyz( Argumenten-Liste )         mit der Function xyz:
      FUNCTION xyz( Parameter-Liste )
 
   Die Elemente der Argumenten-Liste werden der Reihe nach den Elementen
   der Parameter-Liste zugeordnet; sie müssen in Anzahl, Typ und Länge
   (*4, *8 usw.) übereinstimmen.
 
   Für die Übergabe von Werten (Normalfall) gilt:
 
   Die Werte der Argumente bekommen innerhalb des gerufenen Unterprogramms
   die Namen der entsprechenden Parameter. Beim Beendigen (RETURN) des
   Unterprogramms erfolgt die umgekehrte Zuordnung, d.h. die Werte der
   Parameter (die durch das Unterprogramm verändert werden können) haben
   im rufenden Programm wieder die Namen der Argumente.
 
   Achtung: In einer Function sollen die Werte der Parameter nicht ver-
            ändert werden. Nur der Funktionswert soll einen Wert liefern.
 
   Die Feldelemente der Argumenten-Liste bzw. das 1. Element eines Feldes,
   falls dieses angegeben ist, werden dem entsprechenden Feldelement bzw.
   dem 1. Element eines Feldes des Unterprogramms zugeordnet. Dabei ist zu
   beachten, daß das gerufene Feld insgesamt (gemäß seiner Deklarierung)
   nicht außerhalb des übergebenen Feldes zu liegen kommt:
 
        Ein Unterprogramm darf ein übergebenes Feld durch seine
        Dimensionierung nicht vergrößern (nach oben oder unten)
 
   Einer Konstanten, einem Ausdruck, einer DO-Schleifen-Steuergröße darf
   kein Parameter entsprechen, dessen Wert im Unterprogramm geändert wird.
 
   Im Funktions-Unterprogramms muß dem Funktionsnamen (als Variable be-
   trachtet) der gewünschte Funktionswert zugewiesen werden. Nach Beendi-
   gung der Funktion wird dieser Wert als Funktionswert zurückgebracht.
 
   Für die Übergabe von Namen von Unterprogrammen gilt:
 
   Diese werden mit "EXTERNAL UProg-Liste" im rufenden Programm deklariert.
   Diese Unterprogramme bekommen innerhalb des gerufenen Unterprogramms
   die Namen der entsprechenden Parameter und werden dort mit diesen Namen
   aufgerufen. Alle externen Unterprogramme, die zum selben Parameter
   gehören, müssen dieselbe Parameter-Liste (Anzahl, Typ, Länge) besitzen.
 
 
 
 
 
 
 
   -  62 -                 Kapitel 6: Unterprogramme                  -  62 -
 
           Gültigkeitsbereich von Namen
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Die in einem Fortran-Programm (Hauptprogramm plus evtl. Unterprogramme)
   enthaltenen Namen lassen sich einteilen in lokale Namen / globale Namen:
   lokal sind:
               einfache Variable
               Feldvariable, Feldelemente
               Anweisungsnummern, Formatnummern
   global sind:
               Standard-Funktions-Namen (Namen der eingebauten Funktionen)
               Unterprogramm-Namen ( Function-Namen, Subroutine-Namen )
 
   Lokale Namen sind nur innerhalb der eigenen Programmeinheit bekannt;
   außerhalb derselben bezeichnet jeder Name (auch ein gleichlautender)
   ein  anderes  Objekt (einen anderen Speicherplatz).
 
   Globale Namen sind in allen Programmeinheiten bekannt (können von allen
   Programmeinheiten aus aufgerufen werden).
 
   Mischform: Der Funktions-Name ist global (von allen Programmeinheiten
   aus aufrufbar), aber auch gleichzeitig lokal, denn er wird bei der
   Zuweisung des Funktionswertes wie eine einfache Variable behandelt.
 
           Aufgaben (Fortsetzung von S. 58)
           ¯¯¯¯¯¯¯¯
   8. Schreiben Sie eine Subroutine, die m*n INTEGER-Werte in einer Matrix
     speichert. Man setze n und m als maximal 10 voraus. Das Hauptprogramm
     liest zunächst die aktuellen Werte n,m; sodann n*m weitere Werte.
     Die ersten n Werte sollen in die 1. Zeile, die zweiten in die 2.
     Zeile usw. der Matrix gestellt werden. Die Subroutine hat folgende
     6 Parameter: die Dimensionen der Matrix wie im rufenden Programm;
     die aktuellen Dimensionen n,m; der Vektor für die n*m Werte; die
     Matrix, in die die Werte gestellt werden.
 
   9. Schreiben Sie eine Subroutine MERGE zum Mergen von 2 aufsteigend
     sortierten INTEGER-Mengen. Deren Zahl der Werte soll der Subroutine
     übergeben werden. Die Subroutine soll ein Feld aufbauen, das die
     Menge beider Mengen (aufsteigend) enthalten soll. Verfahren:
     Man betrachte der Reihe nach jeweils ein Element der einen und der
     anderen Menge und lege das kleinste von beiden in die Vereinigungs-
     menge ab. Im Hauptprogramm seien n,m maximal gleich 10.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
   -  63 -                Kapitel 7: Ein- und Ausgabe                 -  63 -
 
 
                          Kapitel 7: Ein- und Ausgabe
                          ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
           Fragen
 
   1. 3 grundlegende Fragen, die immer bei Ein- und Ausgabe auftauchen:
      a) Von welchem E/A-Gerät werden die Daten gelesen bzw. auf welches
         werden sie geschrieben?
      b) In welcher Form sollen die Daten ein- bzw. ausgegeben werden?
      c) Welche Variablen bekommen bzw. liefern einen Wert?
   2. Was bedeutet "formatfreie" Ein- und Ausgabe, was "formatierte"
      Ein- und Ausgabe?
 
           Eingabe
           ¯¯¯¯¯¯¯
   Die Antwort auf die 3 Fragen oben:
   zu a):
        Eingabe-Geräte können sein:
 
        Kartenleser, (Fernschreiber-) Lochstreifen (veraltet)
        Bildschirm (Tastatur), Magnetband, Magnetkassette, Magnetplatte
                                              (größere Rechner)
        Bildschirm / Fernseher (Tastatur), Diskette, Festplatte, Maus
                                              (typisch für Microcomputer)
 
        Im Kurs haben wir den Bildschirm mit Tastatur zur Verfügung.
        Mit entspr. Fortran-Anweisungen (OPEN, s.u.) können wir die auf
        den genannten Geräten eingerichteten Datenbestände (Files auf
        Diskette bzw. Festplatte) mit dem Fortranprogramm verbinden.
        Ohne besondere Anweisungen nimmt Fortran an, daß die Daten vom
        Bildschirm kommen; dies nennt man "Standard-Eingabe"; sie hat in
        Fortran als Geräte-Nummer 5 oder einen * (s. u.).
   zu b):
        Was wir eintippen und als Daten einlesen, sind die Zeichen der
        Tastatur; das Fortranprogramm muß z.B. entscheiden, ob eine
        getippte Ziffer Teil einer Zahl oder Teil eines Wortes sein soll;
        muß Dezimalpunkte und Exponenten berücksichtigen und die einzelnen
        Elemente auseinanderhalten. Wie das geschehen soll, wird im Pro-
        gramm definiert (FORMAT) oder kann Teil der Daten selbst sein.
        Ersteres heißt "formatierte Eingabe", letzteres "formatfreie
        Eingabe".
   zu c):
        Dies wird ausschließlich durch das Programm bestimmt, nämlich
        durch die Liste der Variablen in der READ-Anweisung.
 
   Formatfreie Eingabe haben wir bisher mit der Anweisung "READ*,..."
   kennengelernt. Dabei spielte der genaue Ort (Spalte), wo die Daten
   geschrieben waren, keine Rolle, nur die Reihenfolge.
   Bei der formatierten Eingabe (FORMAT-Anweisung; kann auch Teil der
   READ-Anweisung sein, s.u.) wird genau festgelegt, in welche Spalten
   welcher Zeile das Eingabe-Datenelement geschrieben werden muß.
   Außerdem können wir angeben, was geschehen soll, wenn ein READ keine
   Daten, überhaupt keine oder keine mehr, findet.
 
           Formen der READ-Anweisung
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Im folgenden kommt die Eingabe vom Bildschirm (Standard-Einheit 5):
 
     formatfrei                       formatiert
 
     READ*, E/A-Liste                 READ(*,n) E/A-Liste
                                    n FORMAT( Formatinfo )
 
   -  64 -                Kapitel 7: Ein- und Ausgabe                 -  64 -
 
   dass. mit expliziter Geräte-Angabe * bzw. 5:
 
     READ(*,*) E/A-Liste              READ(UNIT=5,FMT=n) E/A-Liste
                                    n FORMAT( Formatinfo )
 
   zusätzl. Angabe einer Anweisungsnummer für "Datenende":
 
     READ(*,*,END=e) Variablen-Liste  READ(UNIT=5,FMT=n,END=e) Var.-Liste
   e ...                            n FORMAT( Formatinfo )
                                          e ...
 
   Die E/A-Liste ist eine Variablen-Liste; sie besteht aus durch Komma
   getrennten Variablen, oder auch aus impliziten DO-Schleifen, s. Kap. 4.
   Der erste * im formatfreien READ bedeutet soviel wie "Standard-Einheit"
   d.h. Einheit 5 (Bildschirm); der 2. Stern bedeutet "formatfrei".
 
           Formatfreie Eingabe
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Die Daten werden durch Komma, Leerzeichen oder Zeilenende voneinander
   getrennt. Sie werden der Reihe nach den Variablen der Eingabe-Liste
   zugewiesen. Ein READ liest immer mind. eine neue Zeile ein; wenn diese
   zu wenige Daten enthält, werden automatisch weitere Zeilen eingelesen.
 
   Wiederholungsfaktor:
   Anstelle eines einzelnen Wertes kann auch w*wert stehen, wo w eine
   ganze Zahl >= 1 ist. Dies ist gleichbedeutend mit dem Niederschreiben
   von w durch Leerzeichen oder Komma getrennten identischen Werten.
   Beispiel: READ*, (A(I),I=1,100)  mit den Daten   100*0.0
   füllt das Feld A mit 0.0
 
   Nullelement ( Leerelement ):
   Zwei aufeinanderfolgende Kommas stellen ein Nullelement dar. Die diesem
   entsprechende Variable bekommt keinen neuen Wert (behält ihren alten).
   Beispiel: READ*, A,B,C   mit den Daten
                    1,,3
   gibt A den Wert 1, C den Wert 3, B bleibt ungeändert
 
   Nullelement mit Wiederholungsfaktor:
   Beispiel: READ*, (A(I),I=1,100)  mit den Daten
                    99*, 0.0
   führt dazu, daß das Feld A ungeändert bleibt bis auf A(100)=0.0
 
   Datenende:
   /  beendet Dateneingabe und READ-Anweisung; alle noch anstehenden
      Eingabe-Variablen behalten ihren alten Wert (Wirkung wie die
      Angabe von Nullelementen für die restlichen Variablen).
   NB: Am PC-Schirm führt  Strg_z  zu End-Of-File (END=e wird ausgeführt).
       Fehlt END=... , so resultiert ein Error (abzufangen mit ERR=r)
 
           Einlesen einer unbekannten Anzahl von Daten
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Dazu gibt es 3 Methoden:
   1. Als erstes kommt die Anzahl der noch folgenden Eingabe-Datenelemente;
      die Werte der Daten-Elemente können beliebig sein.
   2. Eine bestimmte Zahl (ein bestimmtes Wort) gilt als letztes Element,
      z.B. die Zahl 999999 bei numerischer Eingabe, 'Ende' bei Texteingabe.
      Hier kann dieser eine Wert (dieses Wort) nicht Datenelement sein.
   3. Das READ liest alles, was da ist, und merkt selbst, wenn die Daten
      zu Ende sind (keine Beschränkung für die Werte der Datenelemente).
 
   Die Datenelemente werden erst einmal in einem Feld abgespeichert, bevor
   die Verarbeitung beginnt; diese wird durch die CONTINUE-Anweisung unten
   angedeutet. Alle Fehlermöglichkeiten sollen eine Meldung produzieren.
   -  65 -                Kapitel 7: Ein- und Ausgabe                 -  65 -
 
   Dies ist nur unter Verwendung von END= möglich. Also:
   Regel:         Kein READ ohne END= !
 
          PROGRAM Methode 1
   *  Anzahl auf eine erste extra Zeile; dann die Daten beliebig
          INTEGER MaxAnzahl, Anzahl, i
          PARAMETER (MaxAnzahl = 100)
          INTEGER Feld(MaxAnzahl)
          READ(*,*,END=99) Anzahl
          IF( Anzahl .GT. MaxAnzahl ) THEN
             PRINT*,Anzahl,' Daten passen nicht in',MaxAnzahl,' Plätze'
             PRINT*,'Programm abgebrochen vor dem Einlesen der Daten'
             STOP
          ENDIF
          READ(*,*,END=99) (Feld(i),i=1,Anzahl)
          GOTO 20
      99  PRINT*,'Zu wenig Daten! Nur',i,' - 1 statt',Anzahl,': STOP'
          STOP
      20  PRINT*,i,' Daten gelesen einschl. Endekennung'
           continue
          END
 
          PROGRAM Methode 2
   *  je 1 Datenelement pro Zeile, Einlesen bis Endekennung (hier 999999)
          INTEGER MaxAnzahl, Endekennung, i
          PARAMETER (MaxAnzahl = 100, Endekennung = 999999)
          INTEGER Feld(MaxAnzahl)
          DO i=1,MaxAnzahl
            READ(*,*,END=99) Feld(i)
            IF( Feld(i) .EQ. Endekennung ) GOTO 20
          ENDDO
          PRINT*,Maxanzahl,' Daten gelesen; Endekennung nicht gefunden'
          STOP
      99  PRINT*,'Zu wenig Daten: ',i,' - 1: Endekennung nicht gefunden'
          STOP
      20  PRINT*,i,' Daten gelesen einschl. Endekennung'
           continue
          END
 
          PROGRAM Methode 3
   *  Daten beliebig, Einlesen bis EOF
          INTEGER MaxAnzahl,i
          PARAMETER (MaxAnzahl = 100)
          INTEGER Feld(MaxAnzahl)
          READ(*,*,END=99) (Feld(i)), i=1,MaxAnzahl)
          PRINT*,'Es wurden',MaxAnzahl,' Daten eingelesen'
          GOTO 20
       99 PRINT*,'Es wurden',i,' - 1 Daten eingelesen. Ende der Daten'
       20  continue
          END
 
   Bemerkungen:
   1. Die PARAMETER-Anweisung (s.a. Kap. 6 Beispielprogramm) ist bequem,
      um anschließend die Dimensionierung von Feldern zentral abändern zu
      können. Die Dimensionierung erfolgt in den obigen Beispielen mit
      dem "Parameter" (eigentlich: mit der Konstanten) MaxAnzahl.
   2. Die CONTINUE-Anweisung ist eine sog. Leeranweisung (bewirkt nichts).
   3. Die DO-Variable i, die die eingelesenen Daten zählt, hat beim
      Auftreten von EOF bereits um 1 weitergezählt und gibt in diesem
      Fall die Zahl der eingelesenen Daten + 1 an.
   4. Warum haben wir nicht "PRINT*,'Es wurden ',i-1',' Daten gelesen'
      geschrieben, statt dessen oben immer '...',i,' - 1 Daten ...' ?
      In welchen Fällen führt ...,i-1,... zu einer Fehlermeldung?
   -  66 -                Kapitel 7: Ein- und Ausgabe                 -  66 -
 
           Formatierte Eingabe: Die Grundgedanken
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Die formatierte Eingabe ( Standard-Eingabe Gerät Nr. 5 wie oben )
   hat die Form:
           READ(*,'( Formatinfo )') Variablen-Liste
   oder
           READ(*,FMT=n) Variablen-Liste
       n   FORMAT( Formatinfo )
   Die FORMAT-Anweisung ist wie eine Typ-Anweisung eine Definition (des
   Eingabevorgangs) und logisch eigentlich ein Teil der READ-Anweisung.
   Vergibt man eine Anweisungsnummer für eine extra FORMAT-Anweisung, so
   können mehrere READ-Anweisungen dieselbe FORMAT-Anweisung verwenden.
   Die FORMAT-Anweisung kann überall im Programm geschrieben werden.
   Empfehlenswert ist es, alle Formate am Anfang oder alle am Ende des
   Programms zu sammeln.
 
   Das Format enthält im wesentlichen Information der Art:
     "ab Spalte ... ist der Wert der nächsten Variablen aus den nächsten
      ... Spalten zu entnehmen"
 
   Beispiel:
   Einlesen einer ganzen Zeile (maximale Länge 80) in eine Variable vom
   Typ CHARACTER der Länge 80 (s. Kap. 8):       oder
          CHARACTER*80 Zeile
          READ(*,100) Zeile                    READ(*, '(A)' ) Zeile
      100 FORMAT(A)
 
   Der Buchstabe A als Formatinfo bedeutet für das READ:
   lies eine neue Zeile von Anfang an als Character der Länge, wie es die
   Variable in der Liste (hier die Variable Zeile) angibt.
   Es werden also in diesem Fall 80 Zeichen so in die Variable Zeile
   gestellt, wie sie am Bildschirm erscheinen.
 
   Beim Vergleich formatierte Eingabe mit formatfreier Eingabe ergibt sich,
   daß das Schreiben größerer Datenmengen im freien Format Tippfehler
   verzeiht, die mit der nicht genau eingehaltenen Spalte für die
   einzelnen Daten entstehen. Bei numerischen formatierten Daten würden
   sich sonst katastrophale Veränderungen der betr. Werte ergeben.
   Nichtnumerische Daten (Textdaten) sind freilich in Hochkommata
   einzuschließen.
   Aus diesem Grunde wird die Formatsteuerung im einzelnen erst im
   folgenden Kapitel beschrieben; die Logik der Ausgabe mit Format ist
   dann analog auf die Eingabe anzuwenden.
 
           Übungen
           ¯¯¯¯¯¯¯
   1. Lesen Sie eine unbekannte Zahl von INTEGER-Werten (je 1 pro Zeile)
      und bestimmen Sie den größten und den kleinsten Wert. Drucken Sie
      jeden eingelesenen Wert und am Ende die beiden Ergebnisse.
      Version a) Verwenden Sie kein Feld
      Version b) Speichern Sie zuerst alle Werte in einem Feld.
      Achten Sie darauf, daß in keinem denkbaren Fall das Programm mit
      *ERR* abbricht, d.h. fangen Sie alle Fehlermöglichkeiten ab.
 
   2. Schreiben Sie ein Programm zur Lösung des linearen Gleichungssystems
                     Ax + By = C
                     Dx + Ey = F
      Lesen Sie die Werte A,B,C aus der 1. Zeile, D,E,F aus der 2. Zeile.
      Testen Sie Ihr Programm mit einer unbekannten Anzahl von Zeilen.
      Die Lösung nach der Cramerschen Regel ist:
        X = ( CE - BF ) / D ; y = ( AF - CD ) / D ; D = AE - BD
      Vergessen Sie nicht den Fall Determinante D=0 (Nenner=0) !
 
   -  67 -                Kapitel 7: Ein- und Ausgabe                 -  67 -
 
           Ausgabe
           ¯¯¯¯¯¯¯
   Die Antwort auf die 3 Fragen vom Anfang des Kapitels:
   zu a):
        Ausgabe-Geräte können sein:
 
        Kartenstanzer, (Fernschreiber-) Lochstreifen (veraltet)
        Bildschirm,  Magnetband, Magnetplatte (typisch für
                                                        größere Rechner)
        Diskette, Datasette, Bildschirm / Fernseher (typisch
                                                     für Microcomputer)
 
        Im Kurs haben wir Bildschirm und Disketten / Festplatte(n)
        zur Verfügung. Mit entspr. Fortran-Anweisungen (OPEN) können wir
        diese Geräte mit dem Fortranprogramm verbinden.
        Ohne besondere Anweisungen nimmt Fortran an, daß die Daten auf
        dem Bildschirm angezeigt werden: dies heißt "Standard-Ausgabe";
        sie hat in Fortran als Geräte-Nummern 6 oder *, s.u.
        Anstelle der allgemeinen WRITE-Anweisung mit Angabe der Geräte-Nr.
        kann "PRINT*" verwendet werden und bezieht sich dann nur auf die
        Standard-Ausgabe (Bildschirm als vorläufiges Medium statt Drucker).
   zu b):
        Die Ausgabe besteht aus einer Folge von Zeichen, die am Bildschirm
        sichtbar (auf dem Drucker druckbar) sind, sodaß diese auch direkt
        gelesen und verstanden werden können.
        Im Idealfall müßten die eingelesenen Werte in derselben Form wieder
        ausgegeben werden bzw. die ausgegebenen Werte müßten wieder lesbar
        sein und den ursprünglichen Zustand der Werte der Variablen
        wieder herstellen.
        Das ist tatsächlich bei der formatfreien Ein- und Ausgabe der
        Fall, wenn es sich um numerische (und logische) Daten handelt:
        Sie brauchen nur READ*, in PRINT*, oder umgekehrt zu ändern.
        Bei Verwendung von Formaten ist das Vertauschen von READ und
        WRITE mit gewissen Einschränkungen verbunden (s.u. Stichwort
        Druckervorschubsteuerung), die ja logisch nicht umkehrbar ist.
 
        Bei der Ausgabe vom Typ INTEGER oder Typ REAL müssen zusätzlich
        Dezimalpunkte, Exponenten, Vorzeichen usw. berücksichtigt werden.
        Wie das geschehen soll, ist von Fortran automatisch fest vorgegeben
        ("formatfreie Ausgabe") oder wird mit Hilfe eines Formats im
        Programm definiert ("formatierte Ausgabe"). Formatfreie Ausgabe
        kann ohne Änderung wieder im Freiformat eingelesen werden, s.o.,
        außer Text, der bei der Eingabe in '...' eingerahmt werden muß.
   zu c):
        Dies wird ausschließlich durch das Programm bestimmt, nämlich
        durch die Liste in der WRITE-Anweisung bzw. der PRINT-Anweisung.
        Diese Liste kann nicht nur Variable (einschließlich Feldvariable
        und Feldelemente, eventuell innerhalb von impliziten DO-Schleifen)
        enthalten, sondern auch Konstante und Ausdrücke.
 
   Formatfreie Ausgabe haben wir bisher schon mit der PRINT-Anweisung
   kennengelernt. Dabei spielte der genaue Ort (Spalte), wo die Daten
   geschrieben waren, keine Rolle, nur die Reihenfolge.
   Bei der formatierten Ausgabe wird genau festgelegt, in welche Spalten
   welcher Zeile das Ausgabe-Element plaziert wird. Die Anweisung dazu
   ist die WRITE-Anweisung mit FORMAT-Anweisung (das Format kann auch
   Teil der WRITE-Anweisung sein, s.u.).
 
 
 
 
 
 
   -  68 -                Kapitel 7: Ein- und Ausgabe                 -  68 -
 
           Formen der WRITE-Anweisung
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Im folgenden geht die Ausgabe auf Bildschirm (Standard-Einheit 6):
 
      formatfrei                      formatiert
 
      PRINT*, Variablen-Liste         WRITE(*,FMT=n) Variablen-Liste
                                    n FORMAT( Formatinfo )
 
   dass. mit expliziter Geräte-Angabe * bzw. 5:
 
      WRITE(*,*) Variablen-Liste      WRITE(UNIT=6,FMT=n) Variablen-Liste
                                    n FORMAT( Formatinfo )
                    oder kürzer
                         WRITE(UNIT=6,FMT='( Formatinfo )') Variablen-Liste
 
   Es kann anstelle von  FMT=n  oben auch
                           FMT='( Formatinfo )'
   geschrieben werden.
   Die Variablen-Liste besteht aus einzelnen, durch Komma getrennten
   Konstanten, Variablen oder Ausdrücken.
 
   Der erste * im formatfreien WRITE bedeutet "Standard-Ausgabe-Einheit",
   d.h. Einheit 6 (Bildschirm); der 2. Stern bedeutet "formatfrei".
 
           Formatfreie Ausgabe
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Die Daten werden durch Komma, Leerzeichen oder Zeilenende voneinander
   getrennt. Ein WRITE schreibt immer am Anfang einer neuen Zeile weiter;
   wenn eine Zeile nicht genügend Platz hat, werden weitere Zeilen
   geschrieben.
   Formatfrei geschriebene Ausgabe kann formatfrei wieder eingelesen
   werden, indem man nur "PRINT" (bzw. WRITE") durch "READ" ersetzt und
   die Variablen-Liste beibehält (außer Strings, s.o.).
 
           Formatierte Ausgabe
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Das "Format", d.h. das hinter der Angabe FMT= stehende Formatinfo
   (bzw. das Formatinfo der FORMAT-Anweisung) beantwortet 3 Fragen:
   1. Wie soll die Darstellung der Fortran-Variablen, -Konstanten sein?
      Soll eine INTEGER-Zahl mit oder ohne Vorzeichen ausgegeben werden?
      Wieviele Druckstellen (Plätze auf dem Bildschirm) soll sie belegen?
   2. Ab welcher Spalte soll ausgegeben werden?
   3. In welcher Zeile soll ausgegeben werden, wieviel Zeilen tiefer
      als die letzte Zeile ?
 
           Ausgabe von INTEGER-Zahlen
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Wir spielen die oben genannten 3 Aspekte am Beispiel der Ausgabe einer
   INTEGER-Zahl durch.
 
           Der I-Code
           ¯¯¯¯¯¯¯¯¯¯
   Frage 1 wird mit der Angabe eines I-Codes (I wie INTEGER) beantwortet.
   Der Zahlenbereich geht von ca. +2 bis -2 Milliarden. Also kann eine
   INTEGER-Zahl bis zu 10 Ziffern und ein Vorzeichen, also max. 11 Plätze
   einnehmen. Oft weiß man aber, daß die Zahl kleiner ist und z.B. in 3
   Plätzen darstellbar ist. Der I-Code enthält also noch die Anzahl der
   zu füllenden Plätze, z.B. "I3" für eine INTEGER-Zahl und für 3 Zeichen.
 
   I-Code allg. Form:      Iz      belegt z Zeichen für eine INTEGER-Zahl
 
 
   -  69 -                Kapitel 7: Ein- und Ausgabe                 -  69 -
 
 
           Der T-Code
           ¯¯¯¯¯¯¯¯¯¯
   Zur Klärung der 2. Frage teilen wir dem Compiler die Spalte mit, wo
   die Ausgabe beginnen soll. Beides zusammen:
      WRITE(*,FMT='( T2,I3 )' )  -85
 
   Dies heißt: "Gib die Zahl -85 ab Sp. 2 mit insges. 3 Zeichen aus".
   In Sp. 2-4 kommt also -85 zu stehen.
 
   Betrachten Sie die folgende Anweisung:
            WRITE(*, '( T3,I4,T8,I3 )' )  7294, -38
 
   Ausgabeposition Spalte: 123456789012
   Ausgabe:                  7294 -38
 
   Der T -Formatcode zeigt auf die Position n, wo die Ausgabe beginnen
   soll; ab dieser Spalte belegt der I-Formatcode  z Zeichen für die
   entspr. INTEGER-Zahl.
 
   T-Code allg. Form:      Tn       zeigt auf Spalte n
 
   Was passiert, wenn zuviele oder zu wenig Zeichen reserviert sind?
   Im ersten Fall wird links mit Leerzeichen erweitert; man sagt auch, die
   Zahl wird rechtsbündig in die z Positionen eingestellt. Im 2. Fall, wo
   die Zahl nicht vollständig darstellbar wäre, erscheint z mal ein *.
   Ein positives Vorzeichen wird nicht ausgegeben.
 
   Beispiele:                        Ausgabe ( b steht für blank )
                                     Spalte 1: |
   WRITE(6,FMT='( T4,I4 )') 12345                 ****
   WRITE(6,FMT='( T3,I5 )') 12345                12345
   WRITE(6,FMT='( T2,I6 )') 12345               b12345
   WRITE(6,FMT='(    I7 )') 12345              bb12345
   WRITE(6,FMT='( T4,I4 )')-12345                 ****
   WRITE(6,FMT='( T3,I5 )')-12345                *****
   WRITE(6,FMT='( T2,I6 )')-12345               -12345
   WRITE(6,FMT='(    I7 )')-12345              b-12345
 
 
           Übungen
           ¯¯¯¯¯¯¯
   1. Mit T75,I8: welche Spalte wird als letzte mit I8 belegt?
   2. Schreiben Sie eine Folge von T- und I-Codes, um die Spalten 16-24,
      25 und 80-90 für 3 INTEGER-Zahlen zu belegen.
   3. Schreiben Sie eine FORMAT-Anweisung zu "WRITE(*,100) -123,4567,89",
      sodaß die Zeichen -123456789 in Spalte 8 bis 17 erscheinen.
   4. Mit demselben WRITE sollen die Zeichen "4567 89  -123 " in Spalte 2
      bis 15 erscheinen.
   5. Was kommt heraus mit
          WRITE(6,100) 333,22,1
      100 FORMAT(T10,I3,T10,I2,T10,I1)
 
           Der X -Code
           ¯¯¯¯¯¯¯¯¯¯¯
   Allg. Form:    nX    übergeht n Stellen
 
   Z.B. hat  WRITE(6,'(   1X,   4X    ,I10)' )      dieselbe Wirkung wie
             WRITE(6,'( '' '',''    '',I10)' )           oder
             WRITE(6,'(      5X,      ,I10)' )           oder
             WRITE(6,'(      T6,      ,I10)' )
   Die INTEGER-Zahl wird in Sp. 6-11 geschrieben, Sp. 1-5 werden blank.
 
   -  70 -                Kapitel 7: Ein- und Ausgabe                 -  70 -
 
           Implizite Angabe der Ausgabe-Position
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Ist kein T-Code vorhanden, so bestimmt sich die Ausgabe-Position
   implizit ab Sp. 1 (anfangs) bzw. im Anschluß an die vorhergehende
   Ausgabe. Die folgenden Formate haben alle die gleiche Wirkung:
        (T1,1X,T2,I6,T8,I5)         (T2,I6,T8,I5)
        (T1,1X,T2,I6,I5)            (5X,I6,T8,I5)
        (1X,I6,I5)
 
   Es muß nicht unbedingt von links nach rechts geschrieben werden: z.B.
   die 1. INTEGER-Zahl in Sp. 8-12, die 2. in Sp. 2-7 erreicht man mit
        (T8,I5,T2,I6)
 
           ASA-Drucksteuerzeichen
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Die Schnelldrucker an IBM-Großrechnern (Banddrucker oder Laserdrucker
   im Zeilen-Druckmodus) interpretieren das 1. Zeichen in jeder Zeile
   als Steuerzeichen für den Papiertransport.
   Diese sog. ASA-Steuerzeichen haben folgende Bedeutung:
 
      1           "neue Seite"      am Anfang einer neuen Seite
      +           "alte Zeile"      am Anfang der bereits bedruckten Zeile
      Leerzeichen "neue Zeile"      am Anfang der nächsten Zeile
      0           "1 Leerzeile"     am Anfang der übernächsten Zeile
      -           "2 Leerzeilen"    am Anfang der überübernächsten Zeile
 
   Alle anderen Zeichen in Sp.1 werden als Leerzeichen betrachtet (ergibt
   also eine neue Zeile). Druckt man jedoch z.B. die Zahl 123 ab Sp. 1, so
   erscheint die Zahl 23 auf einer neuen Seite usw.
   Man sorge also dafür, daß jede Zeile ein Leerzeichen in Sp. 1 besitzt,
   und daß die auszudruckenden Daten erst ab Sp. 2 beginnen. Dies erreicht
   man am einfachsten mit
           WRITE(*, FMT='( 1X, ...    )' ) ...
   So wird bei jedem WRITE das Papier auf eine neue Zeile transportiert.
   Eine neue Seite bzw. Doppeldruck erhält man mit
           WRITE(*,FMT='( ''1'', ...    )' )  bzw. FMT='( ''+'', ...
   Alles  in "FORMAT"-Schreibweise:
       WRITE(*,100)...  bzw.     WRITE(*,200)...  bzw.     WRITE(*,300)...
   100 FORMAT( 1X,...)  bzw. 200 FORMAT('1',...)  bzw. 300 FORMAT('+',...)
 
   Will man ASA-Steuerzeichen am PC verwenden, so ist eine OPEN-Anweisung
   mit einem Filenamen mit vorangestelltem "(C)" erforderlich, z.B.
        OPEN(6,FILE='(C)P1.OUT')    bzw.     OPEN(6,FILE='(C)TERMINAL')
   für das File P1.OUT bzw. den Bildschirm.
 
           Übungen
           ¯¯¯¯¯¯¯
   1. Schreiben Sie mindestens 2 weitere Formate mit der Wirkung von
      a) FORMAT('+',T5,I12)
      b) FORMAT(I14,T20,I3)
      c) FORMAT(I12,T1,'0',20X,I3)
   2. Was kommt heraus mit (verifizieren Sie es am Computer):
      a)    WRITE(6,2) 1,2,3
          2 FORMAT(I2,2X,I4,2X,I3)
      b)    WRITE(6,5) 1,2,3
          5 FORMAT(I2,T14,I1,T6,I4)
      c)    WRITE(6,8) -1,-2
          8 FORMAT(I2,T1,I2)
      d)    N=17
            WRITE(6,14) N,MOD(18,N),MOD(N,18),N/3
         14 FORMAT(I2,2X,I4,2X,I3)
      e)    WRITE(6,16) 1234567,INT(SQRT(10000.))
         16 FORMAT(' ',I6,T4,I3)
   -  71 -                Kapitel 7: Ein- und Ausgabe                 -  71 -
 
 
           Ausgabe von REAL-Zahlen
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   REAL-Zahlen können mit oder ohne Exponenten ausgegeben werden. Ohne
   Exponent ist der bei der Ausgabe darstellbare Zahlenbereich nur etwa
   +- 100000 ... 0.000001. Mit Exponent gibt es keine Einschränkungen.
 
           Der F-Code
           ¯¯¯¯¯¯¯¯¯¯
   Der F-Code stellt die Zahlen ohne Exponent dar.
 
   Allg. Form:    Fz.d    REAL-Zahlen, z Zeichen, d Dezimalen rechts vom .
 
   Beispiele:                        Ausgabe ( b steht für blank )
                                     Spalte 1: |
   WRITE(6,FMT='( F7.0 )') 123.45              bbb123.
   WRITE(6,FMT='( F7.1 )') 123.45              bb123.4
   WRITE(6,FMT='( F7.2 )') 123.45              b123.45
   WRITE(6,FMT='( F7.3 )') 123.45              123.450
   WRITE(6,FMT='( F7.4 )') 123.45              *******
   WRITE(6,FMT='( F6.2 )') 123.45              123.45
   WRITE(6,FMT='( F5.2 )') 123.45              *****
   WRITE(6,FMT='( F4.2 )') 123.45              ****
 
           Der E-Code
           ¯¯¯¯¯¯¯¯¯¯
   Der E-Code stellt Zahlen mit Exponent in einfacher Genauigkeit dar.
 
   Allg. Form:    Ez.d    REAL-Zahlen, z Zeichen, d Dezimalen rechts vom .
 
   Beispiele:                        Ausgabe ( b steht für blank )
                                     Spalte 1: |
   WRITE(6,FMT='( E7.0 )') 123.45              *******
   WRITE(6,FMT='( E7.1 )') 123.45              0.1E+03
   WRITE(6,FMT='( E7.2 )') 123.45              .12E+03
   WRITE(6,FMT='( E7.3 )') 123.45              *******
   WRITE(6,FMT='( E7.4 )') 123.45              *******
   WRITE(6,FMT='( E6.2 )') 123.45              ******
   WRITE(6,FMT='( E9.4 )') 123.45              .1234E+03
   WRITE(6,FMT='(E10.5 )') 123.45              .12345E+03
   WRITE(6,FMT='(E11.5 )') 123.45              0.12345E+03
   WRITE(6,FMT='(E12.5 )') 123.45              b0.12345E+03
   WRITE(6,FMT='(E16.8 )') 123.45678           b0.12345680E+03
 
   Man sieht, daß maximal 7 Dezimalen (mit Rundung) herauskommen.
   Die beiden Nullen im letzten Beispiel geben offensichtlich die
   Zahl 123.45678 (8 Dezimalen) nicht richtig wieder.
 
           Der D-Code
           ¯¯¯¯¯¯¯¯¯¯
   Der D-Code stellt Zahlen mit Exponent in doppelter Genauigkeit dar.
 
   Allg. Form:    Dz.d    REAL-Zahlen, z Zeichen, d Dezimalen rechts vom .
 
   Beispiel:                            Ausgabe ( b steht für blank )
                                        Spalte 1: |
   ...,FMT='(D24.16 )')123.4567890123456          b0.1234568000000000E+03
   ...,FMT='(D24.16 )')123.4567890123456D0        b0.1234567890123460E+03
 
   Im 1. Beispiel wird die REAL-Konstante trotz der vielen Ziffern nur
   als einfach genau betrachtet: erst der Zusatz "D0" macht eine doppelt
   genaue Konstante daraus mit maximal 15 Dezimalen.
 
   -  72 -                Kapitel 7: Ein- und Ausgabe                 -  72 -
 
           Der G-Code
           ¯¯¯¯¯¯¯¯¯¯
   Der G-Code stellt die Zahlen entweder ohne Exponent oder automatisch,
   falls erforderlich, mit Exponent dar. Außerdem wird hier nicht die Zahl
   der Dezimalen rechts vom . angegeben, was ja, wie oben an den Beispielen
   ersichtlich, z.T. irreführende Ziffern zur Anzeige bringt.
   Statt dessen wird die Zahl der signifikanten Dezimalen festgelegt, d.h.
   die Zahl aller angegebenen Dezimalen vor und hinter dem . ohne führende
   Nullen. Dies ist der für wissenschaftliche Berechnungen am besten
   geeignete Formatcode für REAL-Zahlen.
 
   Allg. Form:    Gz.s    REAL-Zahlen, z Zeichen, s signifikante Dezimalen
 
   Beispiele (identisch wie oben):   Ausgabe ( b steht für blank )
                                     Spalte 1: |
   wie oben mit F-Code:
   WRITE(6,FMT='( G7.0 )') 123.45              *******
   WRITE(6,FMT='( G7.1 )') 123.45              0.1E+03
   WRITE(6,FMT='( G7.2 )') 123.45              .12E+03
   WRITE(6,FMT='( G7.3 )') 123.45              ***
   WRITE(6,FMT='( G7.4 )') 123.45              ****
   WRITE(6,FMT='( G6.2 )') 123.45              ******
   wie oben mit E-Code:
   WRITE(6,FMT='( G9.4 )') 123.45              123.4bbbb
   WRITE(6,FMT='(G10.5 )') 123.45              123.45bbbb
   WRITE(6,FMT='(G11.5 )') 123.45              b123.45bbb
   WRITE(6,FMT='(G12.5 )') 123.45              bb123.45bb
   WRITE(6,FMT='(G16.8 )') 123.45678           bb123.456800000
 
   wie oben (dort mit D-Code):
   ...,FMT='(G24.16 )')123.4567890123456789    bb123.4568000000000
   ...,FMT='(G24.16 )')123.4567890123456789D0  bb123.4567890123460
 
           Übersicht über alle Formatcodes
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Im folgenden gelten die Abkürzungen:
      z: Anzahl der Zeichen insgesamt zur Darstellung der Zahl     ( > 0 )
      d: Anzahl der Dezimalen rechts vom Dezimalpunkt              ( >=0 )
      s: Anzahl der signifikanten Dezimalen (ohne führende Nullen) ( > 0 )
      w: Wiederholungsfaktor                                       ( > 0 )
 
   Allgemein gilt: z,d,s müssen immer angegeben werden; w kann wegbleiben.
 
   Für INTEGER-Zahlen:      Allg. Form     Darstellungsart
 
        I-Code              wIz         ohne oder mit neg. Vorzeichen
                            wIz.m       minimal m Ziffern ( m <= z )
                                        d.h. evtl. mit führenden Nullen
 
   Für REAL-Zahlen (komplexe Zahlen erfordern 2 Real-Formate):
 
        F-Code              wFz.d       Gleitpunkt
        E-Code              wEz.d       mit E-Exponent einfach genau
                            wEz.dEe     dass., Exponent "E" mit e Stellen
        D-Code              wDz.d       mit D-Exponent doppelt genau
                            wDz.dDe     dass., Exponent "D" mit e Stellen
 
   Für alle Zahlen unabhängig vom Typ und für logische Werte:
 
        G-Code              wGz.s       Gleitpunkt oder mit Exponent
                            wGz.sEe     dass., Exponent "E" mit e Stellen
                            wGz.sDe     dass., Exponent "D" mit e Stellen
 
   -  73 -                Kapitel 7: Ein- und Ausgabe                 -  73 -
 
   Dabei sollte z >= d+7 bzw. z >= s+7 sein, um Exponent mit Vorzeichen,
   Dezimalpunkt usw. unterzubringen; falls der Platz dafür und zusätzlich
   für den ganzzahligen Teil der Zahl nicht reicht, werden *** ausgegeben.
 
   Der G-Code schaltet automatisch auf I (bei Typ INTEGER) oder auf
   F / E / D -Format um. Falls die Zahl im F-Format darstellbar ist, wird
   dieses verwendet, sonst das E bzw. D -Format je nach Typ. Außerdem ist
   hier s die Anzahl der signifikanten Dezimalen statt der Dezimalen rechts
   vom Dezimalpunkt; man kann z.B. ein nur auf 3 Dezimalen genaues Ergebnis
   auch mit 3 Dezimalen (ohne führende Nullen gerechnet) ausdrucken:
   z.B. ergibt 0.0148 mit F8.3 -> 0.015, mit G8.3 -> .148E-01
          aber 1.0148 mit F8.3 -> 1.015, mit G8.3 -> 1.01
 
   Für Strings (Typ CHARACTER):
 
        A-Code              wA         CHARACTER beliebiger Länge
                            wAz        dass. mit Länge z linksbündig
 
   Für logische Werte (Typ LOGICAL), s.a. G-Code:
 
        L-Code              wLz        T für .TRUE., F für .FALSE.
 
   Für hexadezimale Darstellung(auch in DATA-Anweisungen als Wert erlaubt):
 
        Z-Code              Znn        2 Hexa-Ziffern (0-9,A-F) je Byte
 
   Tabulator:
 
        T-Code              Tn         positioniert auf Spalte n
                            TLn        positioniert n Spalten nach links
                            TRn        positioniert n Spalten nach rechts
 
   Überspringen von Positionen:
 
        X-Code              nX         geht n Positionen nach rechts
 
   Skalenfaktor (D-,E-,F-,G-Code):
 
        P-Code              iP         multipliziert bei der Ausgabe mit
                                       10**i ( i: Integer mit Vorzeichen )
 
   Steuerung blank als 0 oder als nicht vorhanden (Voreinstellung: BZ)
 
        BZ    blank im formatierten Eingabe-Feld wird als 0 interpretiert
        BN    blank im formatierten Eingabe-Feld gilt als nicht vorhanden
 
   Steuerung positives Vorzeichen (D-,E-,F-,G-,I-Code)
 
        SP    erzeugt in jedem Fall ein +
        SS    unterdrückt in jedem Fall ein +
        S     überläßt es wieder dem Compiler
 
   Steuerung der Ausführung von autonomen Codes
 
        :     beendet autonome Codes, sobald die E/A-Liste zu Ende ist
 
   Steuerung "neuer Record"
 
        /     "neuer Record", meist gleichbedeutend mit "neue Zeile"
              Regel: gilt auch automatisch zu Beginn jeder E/A-Anweisung
 
 
 
   -  74 -                Kapitel 7: Ein- und Ausgabe                 -  74 -
 
   Feinsteuerung der Bildschirmausgabe (Ausnahme von obiger Regel)
 
        $     Cursor bleibt in seiner Zeile stehen für die folgende Eingabe
              (Fortran90-Standard:   WRITE(...,ADVANCE='NO') ...
   Beispiel:
      WRITE(*, '( 1X,A,I4 / 1X, A,I4 )' )  'i=',I,'j=',J
   schreibt die Werte von I und J untereinander in 2 Zeilen.
      WRITE(*, '( 1X,A I4 // 1X,A,I4 )' )   'i=',I,'j=',J
 
   erzeugt dazwischen eine extra Leerzeile.
 
           Wiederholungsfaktoren, Code-Gruppen
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   ersparen das mehrmalige Hinschreiben desselben Formatcodes. Wiederholen
   kann man auch Gruppen in Klammern eingeschlossener Formatcodes, es ist
       5F6.1          dasselbe wie   F6.1,F6.1,F6.1,F6.1,F6.1     und
       3(F6.1,I3)     dasselbe wie   F6.1,I3,F6.1,I3,F6.1,I3
   Insgesamt sind 7 Klammerebenen erlaubt innerhalb der äußeren Klammer.
 
   Beispiel: Ausdruck eines Feldes von 100 Elementen in der Form
     F( 0)=wert   F( 1)=wert  ...    F(99)=wert,  je 4 Werte pro Zeile
 
         WRITE(6,100) ( '  F(',I, ')=', F(I), I=0,99 )
   100   FORMAT(    4 (  A    ,I2, A  , G12.5 : ) )
 
   Der : verhindert, daß am Ende eine Zeile mit "F(" erzeugt wird.
 
           Übungen
           ¯¯¯¯¯¯¯
   1. Was ergibt sich mit (nachprüfen am Computer!):
      a) WRITE(*,'(   I7  )') -12345
      b) WRITE(*,'(   I5  )') -12345
      c) WRITE(*,'(  F8.2 )')  12345.
      d) WRITE(*,'(  F7.1 )') -123.45
      e) WRITE(*,'(  F9.4 )') .00024E-02
      f) WRITE(*,'( E10.2 )') -.00025
      g) WRITE(*,'( E12.5 )') 2.0006
      h) WRITE(*,'(  F8.0 )') 10.E5
      i) WRITE(*,'(  F9.7 )') 10.E-10
      j) WRITE(*,'(   I4  )') 2.64
      k) WRITE(*,'(  F4.0 )') 3
   2. Ersetzen Sie in 1. c) bis i) und k) jeweils im Formatcode die Buch-
      staben E und F durch G. Was ändert sich?
   3. Bestimmen Sie die Startposition für jedes der folgenden Formatcodes:
      a) FORMAT('0',T5,I8,T2,I3)
      b) FORMAT(F12.7,3X,T20,F8.0,T17,'X=')
      c) FORMAT('1X(I)='/E15.6,T1,'12345')
      d) FORMAT(T5,I8,2X,E15.6,T1,'12345')
   4. Gegeben sei FORMAT('0',2(3I2,3X),3F6.2,3(2X,F8.0)).
      a) Wieviele Gruppen enthält das Format?
      b) Wieviele Formatcodes enthält das Format?
      c) Welches ist der 5. Formatcode?
      d) Welche Spalten gehören zum ersten F8.0?
      e) Welche Spalten gehören zum 13. und 14. Formatcode?
      f) Welche Spalten gehören zum dritten F6.2?
      g) Wenn das 5. Datenelement REAL wäre, würde sich ein Error ergeben?
      h) Mit dem 8. Datenelement 12345.67, welche Zeichen werden erzeugt?
   5. Was kommt heraus mit X=+49 und I=-25 und
      a) WRITE(*,'( ''1'',F3.0,T1,I4)') X**(1./2.),I
      b) WRITE(*,'( ''1'',2(3X,2F4.1,I4,2I5)') 2.,3.,4,5,6,7.,8.,9,10,11
 
 
 
   -  75 -                Kapitel 7: Ein- und Ausgabe                 -  75 -
 
           Aufgaben
           ¯¯¯¯¯¯¯¯
    1. Verwenden Sie formatierte Ausgabe für Kap. 5 Aufg. 5 sowie REAL-
       Zahlen für die Temperaturen usw.. Die Ergebnisse sollen so aussehen:
 
                Mo   Di   Mi   Do   Fr   Sa   So   Durch.  Max   Min
       Woche 1   x    x    x    x    x    x    x       x     x     x
       Woche 2   x    x    x    x    x    x    x       x     x     x
       Woche 3   x    x    x    x    x    x    x       x     x     x
       Woche 4   x    x    x    x    x    x    x       x     x     x
                                                   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
                4-Wochen-Statistik                     x     x     x
 
       Die 4 Zeilen "Woche 1 ..." sollen mit DO i=1,4 und einer
       impliziten DO-Schleife geschrieben werden.
    2. Erweitern Sie die formatierte Ausgabe für eine Tabelle der Werte
       für Kap. 5 Aufg. 6 (Tagesstatistik).
    3. Verwenden Sie die Subroutine von Kap. 6 Aufg. 9 für die folgende
       Aufgabe: Mergen von k 5 Mengen. (man nehme k <= 5 an).
       Das Hauptprogramm soll zunächst den Wert von k einlesen, sodann
       die ersten beiden Mengen, diese mergen, dann die nächste Menge,
       diese mergen usw. Die 1. Datenzeile soll jeweils die Zahl der fol-
       genden Eingabe-Datenelemente enthalten (die allererste enthält k).
 
           Zusammenfassung: Allgemeine Regeln für Formate
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Man unterscheidet autonome Formatcodes und beschreibende Formatcodes:
   Autonome Formatcodes sind solche, die allein eine Wirkung haben:
   / "neuer Record", T "Tabulator", X "Leerstelle", '..' "String-Konstante"
   : "Ende Autonomie, wenn E/A-Liste erschöpft", $ "Cursor bleibt stehen"
   BN BZ "blank = nichts" "blank = 0", SP SS "+ ausgeben" "+ unterdrücken"
   Alle anderen Formatcodes sind beschreibende Formatcodes: Diese sind nur
   in Verbindung mit der E/A-Liste wirksam, also in Verbindung mit einer
   Variablen, Konstanten oder einem Ausdruck (für eine WRITE-Anweisung bzw.
   PRINT-Anweisung) und in Verbindung mit einer Variablen (READ-Anweisung).
 
   Der Mechanismus läuft dann folgendermaßen ab:
 
   1. Zuerst wird ein E/A-Befehl ausgelöst, d.h. "neuer Record"
      (i.a. praktisch gleichbedeutend mit "neuer Zeile")
 
   2. Dann werden die Formatcodes der Reihe nach betrachtet:
      a) handelt es sich um einen autonomen Formatcode, wird er ausgeführt.
      b) wird ein beschreibender Formatcode gefunden, wird aus der
         E/A-Liste der Reihe nach ein Element (eine Variable) zugeordnet.
 
   3. Zu der Kombination "beschreibender Formatcode" und "Variable /
      Konstante / Ausdruck" werden gemäß der Größe z (aus dem Formatcode)
      z Zeichen auf dem Bildschirm / aus der Eingabezeile bzw. z Zeichen
      auf dem Papier / in die Ausgabezeile bestimmt.
 
   4. Dies wiederholt sich solange, bis die E/A-Liste abgearbeitet ist.
 
   5. a) Die anschließend auftretenden autonomen Formatcodes werden
         zusätzlich ausgeführt bis zum nächsten beschreibenden Code.
      b) Ab dem Formatcode : wird dieser Vorgang unterbunden.
 
   6. Enthält die E/A-Liste weniger Variable als beschreibende Formatcodes
      (mit Wiederholungsfaktor bzw. Gruppenwiederholungsfaktor gerechnet),
      so werden die überzähligen beschreibenden Formatcodes ignoriert.
 
 
 
   -  76 -                Kapitel 7: Ein- und Ausgabe                 -  76 -
 
 
   7. Enthält die E/A-Liste mehr Elemente als beschreibende Formatcodes,
      dann wird weiter fortgefahren:
      a) falls keine zusätzliche Klammerung vorhanden ist, wieder von
         vorn (d.h. mindestens mit neuem E/A-Befehl "neuer Record")
      b) falls zusätzliche Klammerung vorhanden ist, bei derjenigen
         Klammer-auf, die zu der letzten inneren (zusätzlichen) Klammer-zu
         gehört, einschließlich Gruppenwiederholungsfaktor, falls vorh.
 
   Zusätzliche E/A-Befehle ("neue Zeile") können als "/" eingefügt werden,
   z.B. wenn mit einem Format mehr als 80 Zeichen bearbeitet werden sollen
   (der Normal-Record (Zeile) hat für Ein- und Ausgabe die Länge 80).
 
 
            Tabellarische Übersicht
            ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Beschreibung der unten verwendeten Begriffe:
 
   Eingabe-Datenelement vom Formatcode erfaßte Eingabe-Zeichen. Sie werden
                        zu einer einzigen Größe (Zahl, String) gemacht.
   Eingabe-Variable     Variable aus der Eingabe-Liste
   erscheint intern ... computerspezifische Darstellung der Typen
                        INTEGER, REAL, COMPLEX, LOGICAL
   ist zulässig intern  wie oben
   Ausgabe-Element      Variable, Konstante oder Ausdruck der Ausgabe-Liste
   erscheint extern ... Darstellung auf dem externen Medium wie z.B.
                        Bildschirm, Drucker, Magnetplatte usw.
 
   Die beschreibenden Codes (Ausgabe):
   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   mit | ist        | falls    |            |    Sonderfälle:
   For-| zulässig   | entspr.  | erscheint  | wenn Zeichenzahl Formatcode
   mat-|als Eingabe-| Eingabe- | intern     |     >        |     <
   Code|Datenelement| Variable | als        | Länge der CHARACTER-Variable
   ____|____________|__________|____________|______________|_______________
       |            |          |            |
    A  | beliebig   | beliebig | wie extern | automatische Anpassung an
       | (character)|          | (character)| Länge der Eingabe-Variablen
   ____|____________|__________|____________|______________ _______________
       |            |          |            |              |
    An | beliebig   | beliebig | wie extern | rechts wird  | rechts mit
       | (character)|          | (character)| abgeschnitten| blank gefüllt
   ____|____________|__________|____________|______________|_______________
       |            |          |            |
    D  | real*8     | real*8   | real*8     | für alle numerischen Formate:
   E,F | real*4     | real*4   | real*4     |
   ____|____________|__________|____________| der zulässige| blank wird
       |            |          |            | Bereich für  | als 0
    G  | real       | real     | real       | die entspr.  | interetiert,
       | integer    | integer  | integer    | Konstanten   | falls nicht
   ____|____________|__________|____________| ist zu       | Formatcode
       |            |          |            | beachten     | BN wirksam
    I  | integer    | integer  | integer    |              |
   ____|____________|__________|____________|______________|_______________
       |            |          |            |
   G,L | logical    | logical  | logical    | erstes T oder F liefert Wert
   ____|____________|__________|____________|______________________________
 
 
 
 
 
 
   -  77 -                Kapitel 7: Ein- und Ausgabe                 -  77 -
 
   Die beschreibenden Codes (Eingabe):
   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   mit | ist        | falls    |            |    Sonderfälle:
   For-| zulässig   | entspr.  | erscheint  | wenn Zeichenzahl Formatcode
   mat-| intern für | Ausgabe- | extern     |     >        |     <
   Code| Ausgabe    |  Element | als        | Zeichenzahl Ausgabe-Element
   ____|____________|__________|____________|______________|_______________
       |            |          |            |
    A  | beliebig   | beliebig | wie intern | automatische Anpassung an
       | (character)|          | (character)| Länge des Ausgabe-Elements
   ____|____________|__________|____________|______________ _______________
       |            |          |            |              |
    An | beliebig   | beliebig | wie intern | rechts mit   | rechts wird
       | (character)|          | (character)| blank gefüllt| abgeschnitten
   ____|____________|__________|____________|______________|_______________
       |            |          |            |              |
    D  | real*8     | real*8   | real mit D |              |
    E  | real*4     | real*4   | real mit E | links        | rechts wird
    F  | real*4     | real*4   | Gleitpunkt | wird         | abgeschnitten
   ____|____________|__________|____________| mit          | und gerundet
       |            |          |            | blank        |
    G  | real       | real     | Gleitpunkt | gefüllt      | falls kein
       |            |          | bzw. real  |              | Platz für
       |            |          | mit D/E    |              | INTEGER-Teil:
       | integer    | integer  | integer    |              | Ausgabe von
   ____|____________|__________|____________|              | Sternchen
       |            |          |            |              |  *******
    I  | integer    | integer  | integer    |              |
   ____|____________|__________|____________|______________|_______________
       |            |          |            |
   G,L | logical    | logical  | T oder F   |     ---            ---
   ____|____________|__________|____________|______________________________
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
   -  78 -                Kapitel 8: Der Typ CHARACTER                -  78 -
 
 
                          Kapitel 8: Der Typ CHARACTER
                          ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
           Fragen
 
   1. Was versteht man unter dem Typ CHARACTER, was unter einem String?
   2. Wie werden Strings definiert und verarbeitet?
   3. Welche Operatoren und Funktionen gibt es zur Stringverarbeitung?
 
           CHARACTER-Werte
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Einzelne Zeichen (engl. character) oder Zeichenketten (engl. strings),
   z.B. "1234", können als Zahl interpretiert werden (mit arithmetischen
   Operationen) oder als Folge von 4 einzelnen Zeichen. Im ersteren Fall
   kann "1234" in einem INTEGER- oder REAL- Ausdruck ohne weiteres auf-
   tauchen; sonst muß die Zeichenkette als CHARACTER deklariert werden.
   Als Werte sind alle Zeichen erlaubt, die durch die Tastatur dargestellt
   werden können; genauer: es sind alle 256 Bitkombinationen möglich, die
   ein Byte annehmen kann.
 
           Konstante, Variable, Ausdrücke
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Eine CHARACTER-Konstante wird geschrieben als eine in Hochkomma einge-
   schlossene Zeichenkette, also z.B. 'a', 'Max', '15.3.1989'.
   Bis zu 255 Zeichen sind zwischen den '...'  zugelassen. Falls die
   Zeichenkette selbst das Hochkomma enthalten soll, muß dieses doppelt
   hingeschrieben werden, also z.B. 'tu''s nicht!', was eine Länge von
   11 Zeichen ergibt. Ausprobieren: PRINT*,'tu''s nicht'
 
   CHARACTER-Variable werden mit dem Typ CHARACTER deklariert, z.B.
       CHARACTER A,B*2
       CHARACTER *4 T, U*2, L*6/'LAENGE'/
       CHARACTER MONAT(4)*4 /'Jan.','Feb.','Mär.','Apr.'/
   Als Länge kann "*1" bis "*255" verwendet werden; "*1" kann wegbleiben.
 
   Zuweisung:
         CHARACTER A*n, B*m           n,m sind Zahlen von 1 bis 255
         A = B               oder A = CHARACTER-Ausdruck
   Ist bei Zuweisung B kürzer als A, wird rechts mit Leerzeichen auf die
   Länge von A aufgefüllt; ist A kürzer, wird rechts abgeschnitten.
   Also: mit A*2 und B*4 wird durch A = 'Otto', B = 'ok' der Inhalt von
           A: 'Ot', B: 'ok  '
 
   CHARACTER-Ausdrücke können mit den folgenden CHARACTER-Operatoren
   gebildet werden:
 
   1. Substring-Angabe (wird hinter den entspr. String gestellt):
      String ( von : bis )
      von,  bis   sind INTEGER. Sie geben den Ausschnitt an, wobei ab der
      1. Position die einzelnen Zeichen gezählt werden. Von  bzw.  bis
      können wegbleiben mit der Bedeutung "von vorn" bzw. "bis hinten":
      String(:bis)  bzw.  String(von:)
 
   2. Konkatenierungs-Operator //   (zwei Schrägstriche)
      String1 // String2     bzw.   ... // ... // ... mit mehreren Strings
      bilden einen einzigen zusammengesetzten String.
 
   Beispiele:
   Es sei CHARACTER A, Name*8 /'Otto'/ deklariert. Dann ist
   Name dasselbe wie Name(:) oder Name(1:) oder Name(:4) oder Name(1:4)
      Name(1:2) = Name(3:4)   ->  'toto'       als Inhalt von Name
      'L' // Name             ->  'LOtto'
      Name = Name(:1)//' '//Name(2:2)//' '//Name(3:3)//' '//Name(4:)
   -  79 -                Kapitel 8: Der Typ CHARACTER                -  79 -
 
           Eingebaute Funktionen zur Stringverarbeitung
           ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Fortran stellt folgende Funktionen bereit, z.T. vom Typ CHARACTER;
   im folgenden bedeutet "String" eine CHARACTER -Konstante, -Variable,
    -Feldelement oder ein hieraus gebildeter Substring, z.B. Name(3:4):
 
   1. INTEGER FUNCTION INDEX ( String1, String2 )
      Funktionswert ist der INTEGER-Wert n, der das n.te Byte zählt,
      wo String2 (von links her gesehen) beginnt.
      Ist String2 nicht in String1 enthalten, wird 0 zurückgegeben.
 
   2. INTEGER FUNCTION LEN ( String )
      Funktionswert ist die Länge von String.
      Dies ist wichtig innerhalb eines Unterprogramms, um die Länge eines
      Parameters vom Typ CHARACTER zu bestimmen, sodaß dann Substring
      oder Konkatenierung angewandt werden können.
 
   3. INTEGER FUNCTION ICHAR ( zeichen )
      Funktionswert ist die zum Zeichen gehörige Byte-Code-Zahl 0...255
         'a' =>  97, 'A' =>  65, '0' =>  48 im ASCII-Code (PC),
         'a' => 129, 'A' => 193, '0' => 240 im EBCDI-Code (IBM-Großrechner)
 
   4. CHARACTER FUNCTION CHAR ( integerzahl )
      Funktionswert ist die Umkehrung von ICHAR:
      zurückgegeben wird das Zeichen, das zur entspr. Code-Zahl gehört.
      Möglich für integerzahl sind die Zahlen 0 bis 255.
 
   Wie man sieht, sind die Ergebnisse des Vergleichs zweier Strings
   ganz verschieden, je nachdem man am PC oder Workstation ( ASCII-Code )
   oder am IBM-Großrechner ( EBCDI-Code ) sitzt; z.B. Sortieren wäre so in
   Fortran vom verwendeten Computer abhängig.
   Um dem abzuhelfen, gibt es noch die folgenden logischen Funktionen:
 
      LGE(String1,String2)    liefert  .TRUE.  falls  String1 >= String2
      LGT(String1,String2)    liefert  .TRUE.  falls  String1 >  String2
      LLE(String1,String2)    liefert  .TRUE.  falls  String1 >= String2
      LLT(String1,String2)    liefert  .TRUE.  falls  String1 <  String2
   Maßgeblich für diese Funktionen ist der ASCII-Code.
 
   Wenn man also z.B. statt   IF ( NAME1 .GE. NAME2 ) ...
   schreibt:                  IF ( LGE(NAME1,NAME2) ) ...
   dann wird die Stringverarbeitung auf allen Rechnern gleich laufen.
 
   Beispiel 8.1
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Wir lesen eine Zeile von 80 beliebigen Zeichen ein. Sie kann einzelne
   oder mehrere Leerzeichen hintereinander enthalten; dadurch sollen ein-
   zelne Worte getrennt werden. Wir wollen 1 Wort pro Zeile ausdrucken;
   außerdem sollen mehrere hintereinander stehende Leerzeichen durch ein
   einziges ersetzt und die Zeile in dieser Form ausgegeben werden.
 
         PROGRAM P81
   * Beispiel 8.1: Worte trennen
   * liest eine Zeile Länge 80 ein, gibt die einzelnen Worte getrennt aus
   * und gibt außerdem die Zeile mit nur je 1 trennenden Leerzeichen aus
         IMPLICIT NONE
         CHARACTER *80 Zeile, Wort, hole_Wort_aus, Liste(40), NeueZeile
         INTEGER Zeiger, IndexU, Len_Trim, i,j,k
   * Eingabe:
         PRINT*,'Bitte Zeile eintippen'
         READ (UNIT=5,FMT='(A)') Zeile
         PRINT*,'>>> Eingabezeile war:'
         PRINT*,Zeile
   -  80 -                Kapitel 8: Der Typ CHARACTER                -  80 -
 
   * Verarbeitung:
         Zeiger = IndexU( Zeile,' ' )
         IF (Zeiger .EQ. 0) STOP
         DO I=1,80
            Wort = hole_Wort_aus( Zeile(Zeiger:) )
            Liste(I) =  Wort
            Zeiger = Zeiger + Len_Trim(Wort)
            IF ( Wort .EQ. ' ' .OR. Zeiger .GT. 80 ) QUIT
            Zeiger = Zeiger + IndexU( Zeile(Zeiger+1:), ' ')
         ENDDO
   * Ausgabe:
         PRINT*,'>>> Worte untereinander:'
         WRITE(6,'(A)') (Liste(K),K=1,I-1)
         NeueZeile = Liste(1)
         DO J=2,I-1
            NeueZeile = NeueZeile(1:Len_Trim(NeueZeile)) // ' ' // Liste(J)
         ENDDO
         PRINT*,'>>> Zeile mit nur 1 Leerzeichen zwischen den Worten:'
         WRITE(6,'(A)') NeueZeile
         END
 
         CHARACTER FUNCTION hole_Wort_aus *80( Puffer )
   * ein Wort max. Länge 80 aus Puffer ohne leading und trailing blanks
         IMPLICIT NONE
         CHARACTER Puffer *(*)
         INTEGER Anfang, Ende, IndexU
         hole_Wort_aus = ' '
         Anfang = IndexU( Puffer,' ' )
         IF ( Anfang .EQ. 0 ) RETURN
         Ende   = INDEX ( Puffer(Anfang:),' ')
         IF ( Ende   .EQ. 0 ) Ende = LEN(Puffer)
         hole_Wort_aus = Puffer( Anfang:Ende )
         END
 
         INTEGER FUNCTION IndexU( String1,String2 )
   * Wie eingebaute Funktion INDEX, aber mit prüfen auf ungleich
         CHARACTER *(*) String1, String2
         INTEGER L1, L2, I
         L1 = LEN(String1)
         L2 = LEN(String2)
         IF ( L1 .GE. L2 ) THEN
           DO I=1,L1-L2+1
             IF( String1( I : I+L2-1 ) .NE. String2) THEN
               IndexU = I
               RETURN
             ENDIF
           ENDDO
         ENDIF
         IndexU = 0
         END
         INTEGER FUNCTION Len_Trim( C )
   * Länge eines CHARACTER-Strings ohne trailing blanks, minimal 1
         IMPLICIT NONE
         CHARACTER C *(*)
         INTEGER I
         DO I=LEN(C),1,-1
           IF ( C(I:I) .NE. ' ') THEN
             Len_Trim = I
             RETURN
           ENDIF
         ENDDO
         Len_Trim = 1
         END
   -  81 -                Kapitel 8: Der Typ CHARACTER                -  81 -
 
   Kommentar:
   1. Zunächst fällt eins ins Auge: Die Aufgabe läßt sich eindeutig in 5
      Zeilen beschreiben, zur Programmierung ist jedoch ein größerer
      Aufwand erforderlich. Dies ist typisch für Aufgaben mit Strings im
      weiteren Sinne (Textverarbeitung) und gilt nicht nur für Fortran.
   2. Schon zur Lösung solcher doch einfacher Aufgaben ist es zweckmäßig,
      die Funktionen zur Stringverarbeitung durch selbst geschriebene zu
      ergänzen (hole_Wort_aus, IndexU, Len_Trim).
   3. Das Programm ist klar gegliedert mit Kommentaren wie
      * Eingabe: ---  ...  * Verarbeitung: ---  ...  * Ausgabe: ----  ...
   4. Besonders sei das Studium der Führung des Zeigers empfohlen. Dazu
      die folgenden Erläuterungen:
 
      Der Zeiger soll für den Aufruf von hole_Wort_aus jeweils auf dem
      Anfang eines Wortes stehen; zunächst also auf dem 1. Wort:
         Zeiger = IndexU( Zeile,' ' )
 
      Die nächste Zeile dient dazu, den Sonderfall zu behandeln, daß die
      ganze eingegebene Zeile aus Leerzeichen besteht.
 
      Nachdem in der DO-Schleife ein Wort geholt wurde, wird mit
            Zeiger = Zeiger + Len_Trim(Wort)
      auf das 1. Leerzeichen hinter dem gefundenen Wort gesetzt.
 
      Die nächste Zeile beendet die DO-Schleife, falls der Rest der Zeile
      nur aus Leerzeichen besteht oder falls der Zeiger auf 81 steht, was
      dann passieren kann, wenn das letzte Wort bis einschl. Zeichen 80
      geht. QUIT ist ein Vorgriff auf den Fortran90-Standard und macht
      hinter der Anweisung "ENDDO" weiter, dh. verläßt die DO-Schleife
      (im Fortran90 heißt die entspr. Anweisung EXIT).
      Ohne QUIT hätte man schreiben müssen:
                  IF ( Wort .EQ. ' ' .OR. Zeiger .GT. 80 ) GOTO 77
                  Zeiger = Zeiger + IndexU( Zeile(Zeiger+1:), ' ')
               ENDDO
         77    CONTINUE
 
      Anschließend soll der Beginn des nächsten Wortes gefunden werden.
            Zeiger = Zeiger + IndexU( Zeile(Zeiger+1:), ' ')
      IndexU sucht ab dem Zeichen hinter dem, auf welches Zeiger zeigt
            ...(Zeile(Zeiger+1:),...
      nach einem Zeichen ungleich Leerzeichen; durch Addition wird der
      Zeiger auf dieses Zeichen gesetzt. Wenn kein solches Zeichen ge-
      funden wird, liefert IndexU 0, d.h. der Zeiger bleibt ungeändert.
      Das nächste Wort, das hole_Wort_aus holt, wäre dann leer - siehe
      Anweisung  "hole_Wort_aus = ' '" in der FUNCTION hole_Wort_aus.
 
           Aufgaben
           ¯¯¯¯¯¯¯¯
   1. Erweitern Sie obiges Programm, sodaß als Trennzeichen für Worte
      nicht nur Leerzeichen, sondern alle Sonderzeichen betrachtet werden.
   2. Lesen Sie wieder eine Zeile mit bis zu 80 Zeichen ein. Erstellen Sie
      eine Häufigkeitsstatistik der Buchstaben, Ziffern und Sonderzeichen.
   3. Erweitern Sie die Aufgaben 1 und 2, daß nicht nur 1 Zeile, sondern
      beliebig viele bearbeitet werden; benutzen Sie zur Erkennung des
      Endes der Eingabe (der letzten zu verarbeitenden Zeile) eines der
      Verfahren von Kap. 6 (Einlesen einer unbekannten Zahl von Daten).
   4. Erweitern Sie Aufgabe 3 zur Erstellung eines sog. KWIC-Index
      (KeyWordInContext): Zeilen der Länge 80 werden eingelesen; die
      einzelnen Worte sollen in Sp. 31 untereinander ausgegeben werden,
      zusätzlich mit maximal je 30 Zeichen links und rechts vom Wort.
   5. Geben Sie den KWIC-Index nach den Worten (ab Sp. 31) sortiert aus.
   6. Wie 4. und 5., aber das Zeilenende soll den Kontext nicht begrenzen
      (Volltext-KWIC).
   -  82 -                Kapitel 8: Der Typ CHARACTER                -  82 -
 
           Interne Files
           ¯¯¯¯¯¯¯¯¯¯¯¯¯
   Wir schreiben an die Stelle der Geräte-Nr. bei den E/A-Anweisungen READ
   und WRITE eine Variable vom Typ CHARACTER, auch "internes File" genannt.
   Damit kann man einen Typ in einen anderen konvertieren, wobei alle
   Methoden der Formatierung anwendbar sind.
 
   Beispiel 8.2
   ¯¯¯¯¯¯¯¯¯¯¯¯
         PROGRAM P82
   * Beispiel 8.2: READ mit Internem File
   * Wir wollen die Eingabe analysieren und je nach Bedarf
   * anschließend als Integer oder als Real formatieren.
         CHARACTER Eingabe*11
         PRINT*,'bitte "I" und eine INTEGER-Zahl'
         PRINT*,' oder "R" und eine REAL-Zahl eingeben'
         READ(6,'(A)') Eingabe
         IF (Eingabe(1:1) .EQ. 'I' ) THEN
            READ ( UNIT=Eingabe(2:11), FMT='(I10)') IVariable
            PRINT*,'die INTEGER-Zahl war',IVariable
         ELSEIF (Eingabe(1:1) .EQ. 'R' ) THEN
            READ ( UNIT=Eingabe(2:11), FMT='(F10.0)') RVariable
            PRINT*,'die REAL-Zahl war',RVariable
         ELSE
            PRINT*,'bitte nur "I" oder "R"'
         ENDIF
         END
 
   Kommentar:
   Die Eingabezeile wird zunächst als ganzes (maximal 11 Zeichen) im
   A-Format in die CHARACTER-Variable INPUT eingelesen. A-Format heißt:
   keine Konvertierung der Eingabe.
   Je nach "I" oder "R" wird dann mit dem entspr. Format die richtige
   Konvertierung vorgenommen, d.h. aus der eingetippten Zeichenfolge wird
   eine INTEGER- bzw. REAL-Zahl in interner Darstellung gemacht.
   Der umgekehrte Vorgang ist ebenfalls möglich; er bietet sich an, um
   das Problem zu lösen, daß ein Format keine Variablen enthalten kann;
   z.B. wäre es angenehm, je nach Bedarf eine variable Zeichenbreite z
   auszurechnen und das Format entsprechend arbeiten zu lassen; dafür
 
   Beispiel 8.3
   ¯¯¯¯¯¯¯¯¯¯¯¯
   * Beispiel 8.3: WRITE mit Internem File
   * Erstellen eines "variablen" Formats
         CHARACTER VFORM*5 /'(Ixx)'/
   * hier könnte die Berechnung der Größe z für das I-Format folgen ...
   * wir setzen hier IZ einfach auf 8
         IZ = 8
         WRITE ( VFORM(3:4), '(I2)') IZ
   * jetzt steht ' 8' anstelle von xx in VFORM!
         WRITE(6, VFORM ) ...
   *     WRITE(6,'(I 8)') ... wird jetzt ausgeführt!
 
   Die WRITE-Anweisung mit einer CHARACTER-Variablen als "Ausgabe-Gerät"
   konvertiert die INTEGER- (Binär-) Zahl IZ mit dem Formates I2 in den
   Typ Character, d.h. in unserem Fall in ein Leerzeichen und die 8.
   Diese 2 Zeichen werden in die "Unit" VFORM(3:4) geschrieben.
   Neu ist in diesem Zusammenhang auch, daß anstelle des Formats auch eine
   CHARACTER-Variable angegeben werden kann (bisher haben wir ja nur die
   CHARACTER-Konstante '(...)' als Format benutzt).
   Eine CHARACTER-Variable als "Eingabe-Gerät" oder als "Ausgabe-Gerät"
   stellt einen Record (eine Zeile) dar.
 
   -  83 -                Kapitel 8: Der Typ CHARACTER                -  83 -
 
   Ein File aus mehreren Records (Zeilen) wird mit einem CHARACTER-Feld
   geschrieben, z.B. kann CHARACTER*80 IFILE(100) ein internes File mit
   100 Zeilen der Länge 80 darstellen. Das Schreiben und Lesen in und aus
   einem internen File spricht die einzelnen Records (Feldelemente) wie
   üblich mit dem / -Formatcode an (bzw. "neuer Record" bei Wiederholung
   des Formats, s. Kap. 7 oben).
 
   Beispiel 8.4 (WRITE)
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Wir nehmen das Beispiel von Kap. 7 zum Schreiben eines Feldes von 100
   Elementen; wir wollen nachträglich einige Werte mit * kennzeichnen, die
   nach einer zusätzlichen Analyse als bedenklich gelten sollen.
   Wir gehen so vor, daß wir das Feld wie oben schreiben, nur nicht auf die
   Geräte-Nr. 6, sondern in ein internes File. Anschließend bringen wir die
   nötigen Zusätze an den entspr. Stellen an (mit einfachen Zuweisungen)
   und schreiben dann das Ganze auf die Geräte-Nr. 6. Also:
 
   * Beispiel 8.4: WRITE mit Internem File
   * Erstellen einer Seite Ausgabe zunächst im Speicher
   * mit der Möglichkeit, bel. Korrekturen anzubringen
          CHARACTER IFILE*80(25)
          WRITE(IFILE,100) ( 'F(',I, ')=', F(I), I=0,99 )
   *statt WRITE(6,100) ( '  F(',I, ')=', F(I), I=0,99 ) oben
   100    FORMAT(    4 (  A  ,I2, A  , G12.5 : ) )
   * hier könnte die oben erwähnte Analyse folgen
   * das Ergebnis soll sein, daß die Werte F(5) und F(6) markiert werden
   * diese Werte stehen ja in der 2. Zeile Spalte 1-20 und 21-40, also:
           IFILE(2)( 1: 2)='**'
           IFILE(2)(21:22)='**'
   * es wird alles, da schon formatiert (lesbar), im A-Format ausgegeben
           WRITE(6,'(A)') IFILE
   * so einfach ist das?!
 
   Auf diese Weise ist es in Fortran möglich, sowohl probeweise die Eingabe
   erst einmal im A-Format einzulesen, zu analysieren und mit dem passenden
   Format weiterzuverarbeiten (in eine entspr. interne Form bringen), wie
   im Beispiel 8.2, als auch die Ausgabe erst einmal in ein internes File
   zu schreiben und dann beliebige Korrekturen durch direkten Zugriff auf
   jedes einzelne Zeichen vorzunehmen (Zuweisung an einen Substring, z.B.
   INFILE(10)(20:30)='...' verändert "Zeile" 10 Spalte 20 bis 30)
   und am Ende das ganze interne File im A-Format auszugeben, wie in
   den Beispielen 8.3 und 8.4.
 
   Ein letztes Beispiel
   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Beispiel 8.5
   ¯¯¯¯¯¯¯¯¯¯¯¯
   Aufgabenstellung:
   Man schreibe eine Subroutine, die eine beliebige Funktion auf dem
   Bildschirm "plottet".
 
   Dazu folgende Überlegungen:
   Am PC hat man im Textmodus 25 Zeilen a 80 Zeichen zur Verfügung.
   Mit passenden IBM-Grafikzeichen kann man jedoch an jeder Stelle
   unten, mitte, oben unterscheiden, hat dann also 75 mal 80 "Punkte".
   Es sollen 3 Zeichensätze (Punkt, Strich, Quadrat) verwendet werden.
   Für die 3 Zeichensätze bieten sich die folgenden Zeichen an:
   1) CHAR 46,249,96; 2) CHAR 95,196,126; 3) CHAR 220,254,223,
   wo der 1. Wert unten, der 2. mitte, der 3. oben darstellt.
   Es sollen 76 Funktionswerte von 0 bis 7.5 in Schritten von 0.1
   dargestellt werden mit entspr. beschrifteten Achsen.
   Als Option sollen mehrere Kurven (mit neuem Zeichensatz) übereinander
   dargestellt werden.
   -  84 -                Kapitel 8: Der Typ CHARACTER                -  84 -
 
   Achtung: An jeder Stelle des Textbildschirms kann selbstverständlich
   jeweils nur 1 Zeichen stehen, da wir keine Zeichen zur Verfügung haben,
   die je 2 oder alle 3 Versionen eines Punktes gleichzeitig darstellen
   können. Ein Punkt einer Kurve wird auf jeden Fall durch einen neuen ge-
   löscht, wenn der neue Punkt an derselben Stelle des Textschirms steht
   wie der alte (z.B. wenn der alte Punkt "unten" war und der neue "oben").
 
   Man teste mit der Funktion 2*sin(x).
 
         PROGRAM P85
   * Beispiel 8.5: Plot beliebiger Funktionen im PC-Textmodus
   *               mit 3-facher Auflösung (80 x 75 "Punkte")
         IMPLICIT NONE
         INTEGER Ausgabe, Zeichensatz1, Zeichensatz2, Zeichensatz3
         LOGICAL Neu,Alt
         PARAMETER (Ausgabe = 6, Neu = .TRUE., Alt = .FALSE.,
        &    Zeichensatz1 = 1, Zeichensatz2 = 2, Zeichensatz3 = 3)
         EXTERNAL SIN2
   *     external   falls eigene Funktion gemeint ist
   *     intrinsic  für eine Fortran-Funktion (z.B. sin )
 
   *     Aufruf des Plot-Programms
         CALL PLOT ('2*sin(x)', SIN2, Zeichensatz3, Neu)
   *     nach dem Betrachten des Plots muß Enter gedrückt werden
         READ*
         WRITE ( UNIT=Ausgabe, FMT=*) 'Ende des Plots'
         END
 
         REAL FUNCTION SIN2(X)
   *     anstelle des sin basteln wir die Funktion  2*sin
           SIN2 = 2.0*SIN(X)
         END
 
         SUBROUTINE PLOT (Bezeichnung, F , Nr_Z_Satz, neualt)
 
   * plottet jede beliebige Funktion f(x)
   * im Bereich 0 ó x ó 7.5  und  -2.5 ó y ó 2.5; Schrittweite 0.1 und 0.2
   * Auflösung in X-Richtung:  ñ 0.05  (Zeichenbreite = 1 Schritt = 0.1)
   * Auflösung in Y-Richtung:  ñ 0.033 (3 Zeichen _-â = 1 Schritt = 0.2)
   * Der TEXT-Bildschirm (!!) wird auf eine Auflösung von 80 x 75 gebracht
 
   * Aufruf: CALL PLOT ( Bezeichnung, Funktion, Zeichensatz, neualt)
   *         Bezeichnung: max. 12 Character lang
   *         Funktion: Fortran-Funktion oder selbst geschriebene Funktion
   *                   im rufenden Programm muß dann stehen:
   *                   INTRINSIC funktion    bzw. EXTERNAL funktion
   *                   Beispiel s.o.
   *         Zeichensatz: 1: dünn; 2: dick
   *         neualt:  .TRUE. : Bild wird neu geschrieben
   *                 .FALSE. : Bild wird in das alte eingetragen
   *                           evtl. mit anderem Zeichensatz!
 
   * Beschreibung der Parameter:
   *               Bezeichnung hat Länge wie im rufenden Programm
         CHARACTER Bezeichnung*(*)
         REAL F
   *     external f im rufenden Programm
         INTEGER Nr_Z_Satz
         LOGICAL neualt
 
 
 
 
   -  85 -                Kapitel 8: Der Typ CHARACTER                -  85 -
 
   * Beschreibung der lokalen Variablen:
   *   X / Y - Werte der Funktion F
         REAL XWert, YWert
   *   Ausgabe auf Gerät 6 (Bildschirm)
         INTEGER Ausgabe, i,ix
         PARAMETER (Ausgabe =6)
   *   3 Zeichensätze: dünn, mittel, dick (Nr_Z_Satz=1/2/3) je nach Wunsch
         CHARACTER Zeichensatz ( 1:3, -1:+1)
   *     wir numerieren die Zeilen von -12 bis +12 (25 Stück)
   *                    die Spalten von -4 bis +76 (80 Stück)
         CHARACTER Seite(-4:+75, -12:+12),Zeilen ( -12:+12) *80, Symbol
   *   Überlagerung Seite (einzelne Character) und Zeilen (je 80 Character)
         EQUIVALENCE(Seite, Zeilen)
   *             Spalten / Zeilenindex für Seite, vorhergehende Zeile
         INTEGER Spalte, Zeile, Zeile_alt
   *   Definition der Zeichen des dünnen (punktförmigen) ...
         Zeichensatz (1,-1) = CHAR( 46)
         Zeichensatz (1, 0) = CHAR(249)
         Zeichensatz (1,+1) = CHAR( 96)
   *     Zeichensatz (1,+1) = CHAR( 39) falls Funktion steigt, s.u.
   *   Definition der Zeichen des mittleren (strichförmigen) ...
         Zeichensatz (2,-1) = CHAR( 95)
         Zeichensatz (2, 0) = CHAR(196)
         Zeichensatz (2,+1) = CHAR(126)
   *         ... und des dicken Zeichensatzes (ausgefüllte Felder)
         Zeichensatz (3,-1) = CHAR(220)
         Zeichensatz (3, 0) = CHAR(254)
         Zeichensatz (3,+1) = CHAR(223)
         DATA Zeilen/25*' '/
   * Ende der Typdeklarationen und der Zuweisung von Anfangswerten
   * falls neualt = .TRUE. , werden alle 25 Zeilen des Schirms gelöscht
         IF (neualt) THEN
            DO I=-12,+12
               Zeilen(I)=' '
            ENDDO
         ENDIF
   * erstellen x/y-Achsen mit Beschriftung
   *     x-Achse Sp. 0 bis 76 durchziehen
         DO Spalte= 0, 75
   *               in Zeile 0
            Seite ( Spalte, 0) = CHAR(196)
         ENDDO
   * Markierungen alle 10 Stellen
         DO Spalte =0, 75, 10
            Seite (Spalte,0) = CHAR(194)
   *        darunter in Zeile 1 die Ziffern 1 bis 7
            IF(MOD(Spalte,10).EQ.0) WRITE (Seite(Spalte,1),'(I1)')Spalte/10
         ENDDO
   * y-Achse in Zeile -12 bis +12
         DO Zeile =-12, +12
   *       in Sp. 0
            Seite(0, Zeile) = CHAR(179)
         ENDDO
   * Markierungen wie oben
         DO Zeile =-10, +10, 5
            Seite(0, Zeile) = CHAR(180)
   *        davor in Sp. -2 die Ziffern 2,1,0,1,2
            WRITE (Seite( -2, Zeile), '(I1)') ABS(Zeile/5)
   *        ein Minus für die beiden unteren Ziffern
            IF ( Zeile .GT.0 ) Seite(-3,Zeile)='-'
         ENDDO
 
 
   -  86 -                Kapitel 8: Der Typ CHARACTER                -  86 -
 
   * Berechnung der 76 Funktionswerte von 0 bis 7.5 in Schritten von 0.1
         Zeile_alt = 0
         DO ix = 0, 75
   *        damit XWERT niemals unter den wahren Wert fällt
            XWert = ix*0.1000001
   *        Aufruf der Funktion f
            YWert = F(XWert)
   *        die Zeilen dehnen wir mit Faktor 5!
            Zeile =-NINT(YWert *5.0)
   *                nächste ganze Zahl
   * Umsetzung in Zeilen/Spaltenindex, da Zeilen/Spalten 1-10 leer bleiben
            Spalte =ix
   *        prüfen, ob Indizes im richtigen Bereich
   *        wenn ja, Punkt eintragen - obere oder untere Hälfte oder Mitte!
            IF (Zeile .GE. -12 .AND. Zeile  .LE.12
        &      .AND. Spalte .GE. -4 .AND. Spalte .LE. 75) THEN
   *           wir tun jetzt so, als ob der Bildschirm 75 Zeilen hätte ...
               IF ( ABS( YWert*5.0 - NINT(YWert*5.0) ) .LE. 1.0/6.0) THEN
   *              dann liegt YWert in der Mitte des 0.2- Intervalls
                  Symbol = Zeichensatz ( Nr_Z_Satz, 0)
   *              dieses Zeichen füllt die Mitte aus
               ELSEIF ( INT ( YWert*5.0 +0.5) .GT. INT(YWert*5.0)) THEN
   *              dann liegt YWert in der unteren Hälfte des 0.2-Intervalls
                  Symbol = Zeichensatz ( Nr_Z_Satz, -1)
   *              dieses Zeichen füllt das untere Drittel aus
               ELSE
   *              dann liegt YWert in der oberen Hälfte des 0.2- Intervalls
                  Symbol = Zeichensatz ( Nr_Z_Satz, +1)
   *              dieses Zeichen füllt das obere Drittel aus
                  IF(Nr_Z_Satz.EQ.1 .AND. Zeile_alt.GE.Zeile) Symbol = ''''
   *               ' statt ` falls Funktion steigt
               ENDIF
   *        jetzt erst wird das entspr. Zeichen in die Tabelle eingetragen
            Seite(Spalte,Zeile)= Symbol
            ENDIF
            Zeile_alt = Zeile
         ENDDO
   * Ausgabe des ganzen Plots: Überschrift, max. 16 Zeichen
         Zeilen(-12)  (1:16) = Bezeichnung
   *     Drucken zeilenweise in Stücken von je 80 Zeichen
   *     zunächst die ersten 24 Zeilen
         WRITE(UNIT=Ausgabe,FMT=*) ( Zeilen(I), I=-12,+11 )
   *     das 80. Zeichen der letzten Zeile wird nicht gezeigt: der Cursor
   *     bleibt dort stehen (Formatcode $), sodaß der Plot sichtbar bleibt.
         WRITE(UNIT=Ausgabe,FMT= '( A$ )' ) Zeilen(12) ( :79)
   *     weiter mit Taste Enter, s.oben
         END
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
   -  87 -     Anhang A: Kurzbeschreibung der Syntax von Fortran      -  87 -
 
 
               Anhang A: Kurzbeschreibung der Syntax von Fortran
               ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Hier wird nur der im Skriptum behandelte Teil der Syntax beschrieben.
   Angaben in [ ... ] können weggelassen werden.
   Anweisung                              ( | ): Block  Kommentar
   _______________________________________________________________________
   Hauptprogrammstruktur
 
     PROGRAM programmname                      Name des Hauptprogramms
      Deklarationen
      ausführbare Anweisungen
     END
   Unterprogrammstruktur
     [ Typ ] FUNCTION name ( Parameter-Liste ) Kopfzeile der Funktion
      Deklarationen                            (Typ kann auch Character
      ausführbare Anweisungen                      sein)
     END
 
     SUBROUTINE Name [ ( Parameter-Liste ) ]   Kopfzeile der Subroutine
      Deklarationen
      ausführbare Anweisungen
     END
   Deklarationen
     CHARACTER [ * Länge ] Deklarations-Liste  Fortran-Typen
     INTEGER Deklarations-Liste                         .
     REAL Deklarations-Liste                            .
     LOGICAL Deklarations-Liste                         .
     COMPLEX Deklarations-Liste                         .
     REAL*8 Deklarations-Liste                          .
     Typ Dimensions-Liste                      Feldvereinbarung
     DATA Variable / Werte-Liste / [ ... ]     Anfangswerte
     EXTERNAL Funktionsnamen-Liste             Funktionsnamen werden an
                                               ein Unterprogramm übergeben
   Ausführbare Anweisungen
     READ(5,*) E/A-Liste                       formatfreie Eingabe
     READ*,    E/A-Liste                       dass. Kurzform
     WRITE(6,*) E/A-Liste                      formatfreie Ausgabe
     PRINT*,   E/A-Liste                       dass. Kurzform
     READ (UNIT=..,FMT=..) E/A-Liste           dass. mit expliziter
     WRITE (UNIT=..,FMT=..) E/A-Liste                Geräte-Nr. und Format
   n FORMAT ( Formatcodes )                    n: 1 ... 99999 in Sp. 1-5
 
     Variable = Ausdruck                       Zuweisung; arithmetisch,
                                                  logisch oder character
     IF ( logischer Ausdruck ) THEN          ( IF
          ausführbare Anweisungen            |
   [ ELSEIF ( logischer Ausdruck ) THEN  ]   |
   [    ausführbare Anweisungen          ]   |
   [ ELSE                                ]   |
   [    ausführbare Anweisungen          ]   |
     ENDIF                                   ) ENDIF
 
     IF ( log.Ausdruck ) ausführb.Anweisung    Kurzform des IF
 
        X = Anfangswert                        WHILE-Schleife
     WHILE(Bedingung)                        (   solange Bedingung wahr
        ausführbare Anweisungen              |
        IF (Endebedingung) GOTO e           -->evtl.Verlassen der Schleife
        ausführbare Anweisungen              |
        X = X + Schrittweite                 |   Veränderung der Bedingung
     ENDWHILE                                )
   e CONTINUE                                   hier weiter falls   GOTO e
   -  88 -     Anhang A: Kurzbeschreibung der Syntax von Fortran      -  88 -
 
     DO,I=Anfangswert,Endwert[,Schrittweite]    ( DO-Schleife
           ausführbare Anweisungen              |
     ENDDO                                      )
 
     Implizite DO-Schleife in E/A-Liste:
     z.B. READ, ( A(I), I=Anfangswert,Endwert [,Schrittweite] )
 
     Funktionsname ( Argumenten-Liste )           Funktionsaufruf
     CALL Subroutine-Name [ ( Argumenten-Liste ) ] Aufruf einer Subroutine
 
   Stichwort          Kurzbeschreibung
   _______________________________________________________________________
 
   Name               Buchstabe plus bis zu 30 Buchstaben / Ziffern
   Variable           Name bezeichnet eine einfache Variable oder ein Feld
   Deklarations-Liste Variable, wahlweise mit Länge, getrennt durch Komma
   Dimensions-Liste   Feldname, wahlweise mit Länge, gefolgt von der
                      Max-Dimension, getrennt durch Komma
                      oder (von:bis) bzw. (von:bis,von:bis,...)
   Feldname           Name (mit Dimensionsangabe im Deklarationsteil)
   Max-Dimension      (n) oder (n,m)  oder 3,4,5,6,7 Dimensionen
   Werte-Liste        Konstante,getrennt durch Komma;im Freiformat mehrere
     (auch für READ)  Konstante der Form   Wiederholungsfaktor * Konstante
   E/A-Liste          Variable, Konstante, Ausdrücke, getrennt durch Komma
   E/A-Einheit        5: Bildschirm; 6: Schirm oder Drucker (0-99 möglich)
   n in E/A-Anweisung verweist auf das zugehörige FORMAT (*: Freiformat);
                      steht in Sp. 1-5 der FORMAT-Anweisung
   Bedingung          in der WHILE-Schleife: WHILE(Bedingung ) läßt die
                      Schleife laufen, solange die Bedingung erfüllt ist
   GOTO e (Schleife)  Nummer 1. Anweisung hinter der letzten der Schleife
                      1. Schleifenanweisung springt dahin: IF(...) GOTO e
   Formatcodes        autonom ablaufende:  / nX Tn 'text' :
                      /: neuer Record(Zeile); X: Leerzeichen; T: Tabulator
                      beschreibende:wAz wGz.s für Strings bzw. andere Typen
                      nur für den entspr. Typ:  wIz wLz wFz.d wEz.d wDz.d
                      z: Zahl Druckstellen; s: Zahl signifikanter Ziffern
                      (G-Format),  d: Zahl der Ziffern rechts vom .
                      w: Wiederholungsfaktor; dazu Klammerung bis Tiefe 7
   Variable           Name oder Feldelement
   Feldelement        Name(Dimensionsangabe)
   Ausdruck           arithmetischer oder logischer oder character-Ausdruck
   arithm. Ausdruck   Variable / Konstante / numerische Funktionen mit
                      arithmetischen Operatoren und Klammern
   logischer Ausdruck Variable / Konstante / logische Funktionen mit
                      logischen oder Vergleichs-Operatoren und Klammern
   Character-Ausdruck Character -Variable/ -Konstante mit -Operator und ( )
   String-Konstante   '...'; im Text wird ein ' doppelt als '' geschrieben
   integer-Konstante  ganze Zahl wahlweise mit Vorzeichen
   real-Konstante     Zahl mit Dezimalpunkt wahlweise mit Vorzeichen
                      oder mit E oder D und Exponent (auch mit Vorzeichen)
                      1-7 Dezimalen, oder mit E Exponent (einfach genau),
                      8-16 Dezimalen und mit D Exponent (doppelt genau)
   logical-Konstante  .TRUE. oder .FALSE. als logisch "wahr" oder "falsch"
   Argumenten-Liste   Variable, Konstante, Feldelemente, Feldnamen aus dem
                      rufenden Programm:die entspr. Werte werden übergeben
                      Mit EXTERNAL: die entspr. Namen werden übergeben
   Parameter-Liste    Variable, Konstante, Feldelemente, Feldnamen als
                      Platzhalter für die Argumente des rufenden Programms
   arithm. Operator   + - * / ** für Add.,Subtr.,Mult.,Div.,Exponentiation
   Vergleichs-Operator .EQ. .NE. .LT. .GT. .LE. .GE. für = /=  < >  <=  >=
   logischer Operator .NOT. .OR. .AND.  als logisches "nicht" "oder" "und"
   Character-Operator Substring:  (von:bis)  erzeugt entspr. Teilstring
                      Konkatenierung:  //  verkettet 2 Strings zu einem
   -  89 -               Anhang B: Literatur zu Fortran               -  89 -
 
 
                         Anhang B: Literatur zu Fortran
                         ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   Ziehen Sie nur Bücher in Betracht, in denen ausdrücklich der neuere
   Fortran-77-Standard beschrieben ist!
 
   Ein besonders gutes Preis-Leistungsverhältnis weisen die folgenden
   deutschsprachigen Einführungen auf (Signatur der URZ-Bibliothek):
   (Preise Stand: 1986)
 
                                                                 Signatur
   I.Kiessling, M.Lowes: Programmierung mit Fortran 77,            FP8202
                         4. Aufl. 1987, Teubner, DM 16.80
   E.Kaucher et al: Programmiersprachen im Griff:                  FP8303
                      Band 5: Fortran 77, BI, DM 29,80
   E.Kaucher, et al. Programmiersprachen im Griff                  FP8402
                      Band 7: Übungen und Tests in Fortran 77
   G. May: Strukturiertes Programmieren mit Fortran                FP8002
                         Hanser, DM 34.00
 
   Für Fortgeschrittene empfehlenswert:
 
   J.L. Wagener: Fortran 77: Principles of Programming             FP8006
                 John Wiley, (englisch) 61.90
 
   Als Standard-Referenz:
 
   Harry Katzan: Fortran 77, Van Nostrand Reinhold Comp.           FP7802
                (englisch), DM 88.40
 
   Sehr empfehlenswert als Einführung in Fortran und darüber
   hinaus in Programmentwicklung und Anwenden von Software:
 
   Daniel D.McCracken: Computerpraxis mit Fortran77 in Natur-      FP8505
          wissenschaft und Technik, Hanser Verlag 1985, DM 68.-
 
   Programmierstil (mit Ausblick auf den Fortran90-Standard):
 
   Kessel, Stephen R.: Fortran77 Dokumentation and Style,          FP9201
                       Addison & Wesley (englisch)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
   -  90 -               Anhang C: Der WATFOR Debugger                -  90 -
 
 
                         Anhang C: Der WATFOR Debugger
                         ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
 
   Start:  RUN/DEbug
 
   Sie erhalten die Zeilennummer und die erste ausführbare Anweisung.
 
   DEBUG>  fordert Sie auf, ein Debugger-Kommando einzugeben, z.B.
 
   Help            gibt Ihnen eine kurze Übersicht über die Kommandos.
           Anstelle von  isn  (Internal Statement Number) kann stehen:
            . /  n   die momentan angezeigte Anweisung / Anweisung Nr. n
           +n / -n   n Anweisungen vorwärts / rückwärts
 
   Display         listet +- 5 Anweisungen (insgesamt 10)
   Display isn     listet Anweisung Nr. isn
   Display isn:isn listet Anweisungen von:bis
   Display *       listet das ganze Programm
 
   Go              startet die Programmausführung bei der momentanen isn
   Go isn          startet die Programmausführung bei isn
 
                   zeigt die E/A-Geräte an, die geloggt werden
   LOGio unit      listet ab sofort alle Ein- und Ausgabe betreffs unit
                   im Listing bedeutet: < : Eingabe; > : Ausgabe
   LOGio OFF       schaltet aus
 
   Quit            beendet den Debugger, landet im Editor
 
   SET item value  weist der Variablen (Substring) item den Wert value zu
 
   STAtus          zeigt die eingeschalteten Optionen (STOp, Trace, Step)
 
   STEp            Stop bei jeder Anweisung; weiter mit der Enter-Taste
   STEp OVER       dass. ohne Stop bei CALL (Ende Einzelschritt mit Go)
 
   STOp isn        wie Go, stoppt aber bei isn
   STOp isn : isn  dass., stoppt aber bei allen isn im Bereich von:bis
   STOp Calls      dass., stoppt aber nur bei CALL (Unterprogrammaufruf)
   STOp OFF        schaltet ab
 
   SYStem          geht kurz ins DOS (für DOS-Kommandos); EXIT geht zurück
   SYStem command  führt das DOS-Kommando command aus
 
   Trace           schaltet Anzeige aller ausgeführten Anweisungen ein
   Trace isn       dasselbe nur für die Anweisung Nr. isn
   Trace isn : isn dasselbe nur für die Anweisungen von : bis
   Trace Calls     dasselbe, zeigt aber nur die Unterprogrammnamen
   Trace OFF       schaltet ab
 
   Unit            zeigt alle offenen E/A-Geräte und File-Attribute
   Unit unit       dasselbe für Gerät unit (0...99)
 
   Where           Traceback (rufende Programme) und nächste Anweisung
 
   ?               zeigt alle Variablen und ihre Werte; Halt mit Strg_Untbr
   ? fmt var,...   zeigt die Werte der entspr. Variablen; Format kann sein
                   (kann wegbleiben): (A) : A-Format; (Z) : Hexadezimal
 
   Nothalt im laufenden Programm: "Strg_Untbr" (PC), Wirkung wie "Where",
           danach sind bel. Debug-Kommandos möglich
 
   -  91 -          Anhang D: Lösungen zu den Übungsaufgaben          -  91 -
 
 
                    Anhang D: Lösungen zu den Übungsaufgaben
                    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
         PROGRAM Kapitel_1_Aufgabe_1
         INTEGER Summe
         Summe = 127 + 584
         PRINT*,'Die Summe von 127 und 584 ist',Summe
         END
 
         PROGRAM Kapitel_1_Aufgabe_2
         PRINT*,' *****  *   *  *   *   *** '
         PRINT*,' *      ** **  ** **  *   *'
         PRINT*,' *      * * *  * * *  *   *'
         PRINT*,' *****  *   *  *   *  *****'
         PRINT*,' *      *   *  *   *  *   *'
         PRINT*,' *****  *   *  *   *  *   *'
         END
 
         PROGRAM Kapitel_1_Aufgabe_3
         INTEGER Zahl
         PRINT*,'Quadrate und Kuben der Zahlen von 1 bis 20:'
         PRINT*,'        Zahl     Quadrat        Kube'
         Zahl = 1
         WHILE( Zahl .LE. 20)
           PRINT*,Zahl, Zahl*Zahl,Zahl*Zahl*Zahl
           Zahl = Zahl + 1
         ENDWHILE
         END
 
         PROGRAM Kapitel_1_Aufgabe_4
         INTEGER Zahl
         PRINT*,'Quadrate und Kuben der ungeraden Zahlen von 1 bis 20:'
         PRINT*,'        Zahl     Quadrat       Kubus'
         Zahl = 1
         WHILE( Zahl .LE. 20)
           PRINT*,Zahl, Zahl*Zahl, Zahl*Zahl*Zahl
           Zahl = Zahl + 2
         ENDWHILE
         END
 
         PROGRAM Kapitel_1_Aufgabe_5
         INTEGER Lohn, Tag
         Lohn = 1
         Tag = 1
         WHILE( Tag .LE. 30)
           Lohn = 2*Lohn
           Tag = Tag + 1
         ENDWHILE
         PRINT*,'Nach 30 Tagen beträgt der Lohn',Lohn,' Pfennige'
         PRINT*,'Das sind', Lohn/100,' Mark  und',Lohn-Lohn/100*100,
        & ' Pfennige'
         END
 
         PROGRAM Kapitel_1_Aufgabe_6
         INTEGER Jahr
         REAL Schuld, Zinsen
         Schuld = 1000
         Jahr = 1991
 
 
 
 
 
   -  92 -          Anhang D: Lösungen zu den Übungsaufgaben          -  92 -
 
         WHILE( Schuld .GT. 0)
           Zinsen = 0.10*Schuld
           Schuld = Schuld + Zinsen - 200
           PRINT*,'Schuld am Ende des Jahres',Jahr,':',Schuld,' Mark'
           PRINT*,'  An Zinsen müssen',Zinsen,' bezahlt werden'
           Jahr = Jahr + 1
         ENDWHILE
         PRINT*,'Endlich schuldenfrei im Jahr',Jahr
         PRINT*,'Guthaben:',-Schuld,' Mark'
         END
 
         PROGRAM Kapitel_1_Aufgabe_7
         REAL x,y
         x = 0
         WHILE( x .LE. 10 )
           y = ( x*x - x + 2 ) / ( x + 3 )
           PRINT*,'Für x =',x,'     wird y =',y
           x = x + 1
         ENDWHILE
         END
 
         PROGRAM Kapitel_1_Aufgabe_8
         REAL x,y
         x = 1
         WHILE( x .LE. 21 )
           y = 3*x*x - 2*x + 7
           PRINT*,'Für x =',x,'     wird y =',y
           x = x + 2
         ENDWHILE
         END
 
         PROGRAM Kapitel_1_Aufgabe_9
         INTEGER Zahl
         REAL Summe
         Summe = 0
         Zahl = 0
         WHILE( Zahl .LE. 9 )
           Summe = Summe + Zahl**3
           PRINT*,'Wurzel der Summe der Kuben von 0 bis',Zahl,' ist',
        &  SQRT(Summe)
           Zahl = Zahl + 1
         ENDWHILE
         PRINT*,'Die Ergebnisse unterscheiden sich jeweils um 1,2,3, usw.'
         END
 
         PROGRAM Kapitel_1_Aufgabe_10
         INTEGER Zahl1, Zahl2, Summe, Nummer
           PRINT*,'Fibonacci-Zahl Nummer           0 ist', 0
           PRINT*,'Fibonacci-Zahl Nummer           1 ist', 1
         Zahl1 = 0
         Zahl2 = 1
         Nummer = 2
         WHILE( Nummer .LE. 15 )
           Summe = Zahl1 + Zahl2
           PRINT*,'Fibonacci-Zahl Nummer',Nummer,' ist', Summe
           Zahl1 = Zahl2
           Zahl2 = Summe
           Nummer = Nummer + 1
         ENDWHILE
         END
 
 
 
   -  93 -          Anhang D: Lösungen zu den Übungsaufgaben          -  93 -
 
         PROGRAM Kapitel_1_Aufgabe_11
         REAL x
         INTEGER Exponent, Zaehler
         x = 1.25
         Exponent = 1
         Zaehler = 1
         PRINT*,'x=',x
         WHILE( Zaehler .LE. 5 )
           PRINT*,'x hoch',Exponent,' ist', x**Exponent
           Exponent = 2 * Exponent
           Zaehler = Zaehler + 1
         ENDWHILE
         END
 
         PROGRAM Kapitel_1_Aufgabe_12
         REAL x
         INTEGER Exponent, Nenner, Differenz, Zaehler
         x = 1.25
         Exponent = 0
         Differenz = 1
         Zaehler = 1
         PRINT*,'x=',x
         WHILE( Zaehler .LE. 8 )
           Exponent = Exponent + Differenz
           Nenner = Exponent
           PRINT*,'x hoch',Exponent,' durch',Nenner,' ist',
        &          x **    Exponent   /      Nenner
           Differenz = Differenz + 1
           Zaehler = Zaehler + 1
         ENDWHILE
         END
 
         PROGRAM Kapitel_2_Aufgabe_1
         IMPLICIT NONE
         INTEGER i
         i = 1
         WHILE( i .LE. 12 )
           PRINT*, i, 12 - ( 6 - i )
           i = i + 1
         ENDWHILE
         END
 
         PROGRAM Kapitel_2_Aufgabe_2
         IMPLICIT NONE
         REAL x,y
         x = 0.0
         WHILE( x .LE. 2.0 )
           y = ( x**3 - 4*x**2 + x - 3 ) / ABS ( x + 2 )
           PRINT*,'für x=',x,' ist y=',y
           x = x + 0.25
         ENDWHILE
   * um die Ausgabe auf den Schirm anzuhalten
         PRINT*,'weiter mit Enter'
         READ*
         x = -1.0
         WHILE( x .GE. -13.0 )
           y = ( x**3 - 4*x**2 + x - 3 ) / ABS ( x + 2 )
           PRINT*,'für x=',x,' ist y=',y
           x = x - 2.0
         ENDWHILE
 
 
 
   -  94 -          Anhang D: Lösungen zu den Übungsaufgaben          -  94 -
 
   * um die Ausgabe auf den Schirm anzuhalten
         PRINT*,'weiter mit Enter'
         READ*
         x = 10.0
         WHILE( x .GE. -1.0 )
           y = ( x**3 - 4*x**2 + x - 3 ) / ABS ( x + 2 )
           PRINT*,'für x=',x,' ist y=',y
           x = x - 1.0
         ENDWHILE
         PRINT*,'weiter mit Enter'
         END
 
         PROGRAM Kapitel_2_Aufgabe_3
         IMPLICIT NONE
         INTEGER n,Exponent
         REAL x
         PRINT*,'bitte n eingeben'
         READ*,n
         PRINT*,'bitte x eingeben'
         READ*,x
         Exponent = 0
         WHILE( Exponent .LE. n )
           PRINT*,'x /',2**Exponent,' ist',x / 2**Exponent
           Exponent = Exponent + 1
         ENDWHILE
         END
 
         PROGRAM Kapitel_2_Aufgabe_4
         IMPLICIT NONE
         INTEGER n
         n = 20
         WHILE( n .LE. 20 )
           PRINT*,'Summe der ersten',n,' Zahlen N    ist',
        &              n*(n+1)/2
           PRINT*,'Summe der ersten',n,' Zahlen N**2 ist',
        &              n*(n+1)*(2*n+1)/6
           PRINT*,'Summe der ersten',n,' Zahlen N**3 ist',
        &              n**2*(n+1)**2/4
           PRINT*,'Summe der ersten',n,' Zahlen N**4 ist',
        &              n*(n+1)*(2*n+1)*(3*n**2+3*n-1)/30
           PRINT*,'Summe der ersten',n,' Zahlen N**5 ist',
        &              n**2*(n+1)**2*(2*n**2+2*n-1)/12
           n = n + 1
         ENDWHILE
         END
 
         PROGRAM Kapitel_2_Aufgabe_5
         IMPLICIT NONE
         REAL x, Naeherung
         x = 0.5
         WHILE( x .LE. 9.5 )
           Naeherung = (1+4*x) / (4+x)
           PRINT*,'Für x=',x,' ergibt sich als Näherung:',Naeherung
           PRINT*,'Der prozentualer Fehler beträgt',
        &              ( Naeherung - SQRT(x) ) / SQRT(x) *100,' %'
           IF ( x .EQ. 5.0 ) THEN
   * um die Ausgabe auf den Schirm anzuhalten
             PRINT*,'weiter mit Enter'
             READ*
           ENDIF
           x = x + 0.5
         ENDWHILE
         END
   -  95 -          Anhang D: Lösungen zu den Übungsaufgaben          -  95 -
 
         PROGRAM Kapitel_2_Aufgabe_6
         IMPLICIT NONE
         REAL x, Naeherung
         x = 0.2
         WHILE( x .LE. 1.0 )
           Naeherung = -0.076 + 0.281*x - 0.238 / ( x + 0.15 )
           PRINT*,'Für x=',x,' ergibt sich als Näherung:',Naeherung
           PRINT*,'Der absolute Fehler beträgt',
        &         ABS ( Naeherung - LOG10(x) )
           x = x + 0.2
         ENDWHILE
         END
 
         PROGRAM Kapitel_2_Aufgabe_7
         IMPLICIT NONE
         INTEGER Summe,Rest
         INTEGER Tausender, Fuenfhunderter, Zweihunderter, Hunderter,
        &    Fuenfziger, Zwanziger, Zehner, Fuenfer
         Summe = 1575
   * Tausender
         Tausender = Summe / 1000
         Rest = Summe - Tausender *  1000
   * Fünfhunderter
         Fuenfhunderter = Rest / 500
         Rest = Rest - Fuenfhunderter *  500
   * Zweihunderter
         Zweihunderter = Rest / 200
         Rest = Rest - Zweihunderter *  200
   * Hunderter
         Hunderter = Rest / 100
         Rest = Rest - Hunderter *  100
   * Fünfziger
         Fuenfziger = Rest / 50
         Rest = Rest - Fuenfziger *  50
   * Zwanziger
         Zwanziger = Rest / 20
         Rest = Rest - Zwanziger *  20
   * Zehner
         Zehner = Rest / 10
         Rest = Rest - Zehner *  10
   * Fünfer
         Fuenfer = Rest / 5
         Rest = Rest - Fuenfer *  5
         PRINT*,'Man braucht für',Summe,' mindestens an Scheinen:'
         PRINT*,Tausender,' Tausender'
         PRINT*,Fuenfhunderter,' Fünfhunderter'
         PRINT*,Zweihunderter,' Zweihunderter'
         PRINT*,Hunderter,' Hunderter'
         PRINT*,Fuenfziger,' Fünfziger'
         PRINT*,Zwanziger,' Zwanziger'
         PRINT*,Zehner,' Zehner'
         PRINT*,Fuenfer,' Fünfer'
         END
 
         PROGRAM Kapitel_3_Aufgabe_1
         IMPLICIT NONE
         INTEGER Zahl, Zaehler, Ziffer, Expo
         PRINT*,'bitte Zahl eingeben'
         READ*,Zahl
         Zaehler = 0
         Expo = 10
 
 
   -  96 -          Anhang D: Lösungen zu den Übungsaufgaben          -  96 -
 
         WHILE ( Expo .GE. 0 )
           Ziffer = Zahl / 10**Expo
           IF( Ziffer .NE. 0 ) THEN
               Zaehler = Zaehler + 1
               Zahl = Zahl - Ziffer*10**Expo
           ENDIF
           Expo = Expo - 1
         ENDWHILE
         PRINT*,'Zahl der Ziffern ungleich 0:',Zaehler
         END
 
         PROGRAM Kapitel_3_Aufgabe_2
         IMPLICIT NONE
         INTEGER n,m,k, nk,mk
         PRINT*,'bitte 3 Zahlen n,m,k eingeben'
         READ*,n,m,k
         nk = MOD(n,10**k)
         mk = MOD(m,10**k)
         IF( nk .EQ. mk ) THEN
          PRINT*,'die letzten',k,' Stellen von',n,' und',m,' sind gleich'
         ELSE
          PRINT*,'die letzten',k,' Stellen von',n,' und',m,' sind ungleich'
         ENDIF
         END
 
         PROGRAM Kapitel_3_Aufgabe_3
         IMPLICIT NONE
         INTEGER a,b,c
         PRINT*,'bitte 3 Seitenlängen eingeben'
         READ*,a,b,c
         IF( a .GT. b+c .OR. b .GT. a+c .OR. c .GT. a+b
        & .OR. a .EQ. 0 .OR. b .EQ. 0 .OR. c .EQ. 0 ) THEN
          PRINT*,'das gibt kein Dreieck'
          PRINT*,0
         ELSEIF( a .NE. b .AND. a .NE. c .AND. b .NE. c ) THEN
          PRINT*,'alle Seiten ungleich'
          PRINT*,1
         ELSEIF( a .EQ. b .AND. b .EQ. c .AND. c .EQ. a ) THEN
          PRINT*,'alle Seiten gleich'
          PRINT*,3
         ELSEIF( a .EQ. b .OR. a .EQ. c .OR. b .EQ. c ) THEN
          PRINT*,'2 Seiten gleich'
          PRINT*,2
         ENDIF
         END
         PROGRAM Kapitel_3_Aufgabe_4
         IMPLICIT NONE
         REAL Zahl, low, high, mid
         Zahl = 12.0
         low = 3.0
         high = 4.0
         WHILE( high - low .GE. 0.02 )
           PRINT*,'low - high:',low,high
           mid = ( low + high ) / 2.0
           IF ( mid**2 .GT. Zahl ) THEN
             high = mid
           ELSE
             low = mid
           ENDIF
         ENDWHILE
         PRINT*,'Näherung für Wurzel aus 12:',mid
         PRINT*,'SQRT(12)=                  ',SQRT(12.0)
         END
   -  97 -          Anhang D: Lösungen zu den Übungsaufgaben          -  97 -
 
         PROGRAM Kapitel_3_Aufgabe_5
         IMPLICIT NONE
         INTEGER Jahr,Monat,Tag,  J,M,T,  Wochentag,K
         PRINT*,'Berechnung des Wochentags aus dem Datum'
         WHILE ( Jahr .GE. 0 )
           PRINT*
           PRINT*,'bitte Jahr eingeben'
           READ*,Jahr
           PRINT*,'bitte Monat eingeben'
           READ*,Monat
           PRINT*,'bitte Tag eingeben'
           READ*,Tag
           IF ( Monat .EQ. 1 .OR. Monat .EQ. 2 ) THEN
             M = Monat + 12
             J = Jahr - 1
           ELSE
             J = Jahr
             M = Monat
           ENDIF
           T = Tag
           K = T + 2*M + (3*M +3) / 5 + J + J/4 + J/100 + 1
           Wochentag = MOD(K,7)
           IF ( Wochentag .EQ. 1 ) THEN
             PRINT*,'Der Tag ist ein Montag'
           ELSEIF ( Wochentag .EQ. 2 ) THEN
             PRINT*,'Der Tag ist ein Dienstag'
           ELSEIF ( Wochentag .EQ. 3 ) THEN
             PRINT*,'Der Tag ist ein Mittwoch'
           ELSEIF ( Wochentag .EQ. 4 ) THEN
             PRINT*,'Der Tag ist ein Donnerstag'
           ELSEIF ( Wochentag .EQ. 5 ) THEN
             PRINT*,'Der Tag ist ein Freitag'
           ELSEIF ( Wochentag .EQ. 6 ) THEN
             PRINT*,'Der Tag ist ein Samstag'
           ELSE
             PRINT*,'Der Tag ist ein Sonntag'
           ENDIF
         ENDWHILE
         PRINT*,'Stop nach negativem Jahr'
         END
         PROGRAM Kapitel_3_Aufgabe_6
         IMPLICIT NONE
         INTEGER Zahl, Ziffer1, Ziffer2, Ziffer3
         INTEGER Zahl1, Zahl2, Zahl3, Zahl4, Zahlen, Zeilen
         Zahl   = 100
         Zahlen = 0
         Zeilen = 0
         WHILE ( Zahl .LE. 500 )
           Ziffer1 = Zahl / 100
           Ziffer2 = MOD(Zahl,100) / 10
           Ziffer3 = MOD(Zahl,10)
           IF(Ziffer1 .NE. Ziffer2 .AND. Ziffer2 .NE. Ziffer3 .AND.
        &     Ziffer3 .NE. Ziffer1 ) THEN
             Zahlen = Zahlen + 1
             IF ( Zahlen .EQ. 1 ) THEN
               Zahl1 = Zahl
             ELSEIF ( Zahlen .EQ. 2 ) THEN
               Zahl2 = Zahl
             ELSEIF ( Zahlen .EQ. 3 ) THEN
               Zahl3 = Zahl
             ELSEIF ( Zahlen .EQ. 4 ) THEN
               Zahl4 = Zahl
           ENDIF
   -  98 -          Anhang D: Lösungen zu den Übungsaufgaben          -  98 -
 
           IF( Zahlen .EQ. 4 ) THEN
             Zeilen = Zeilen + 1
             PRINT*,Zahl1,Zahl2,Zahl3,Zahl4
             Zahlen = 0
             IF( Zeilen .EQ. 23 ) THEN
               Zeilen = 0
               PRINT*,'weiter mit Enter'
               READ*
           ENDIF
           Zahl = Zahl + 1
         ENDWHILE
         END
 
         PROGRAM Kapitel_4_Aufgabe_1
         IMPLICIT NONE
         REAL x, y
         INTEGER I
         DO I= 1,20
           x = I
           y = (x**2 - x + 7) / (x**2 + 2)
           PRINT*,'für x=',x,' ist y=',y
         ENDDO
         PRINT*,'weiter mit Enter'
         READ*
         DO I= 3,24,3
           x = I
           y = (x**2 - x + 7) / (x**2 + 2)
           PRINT*,'für x=',x,' ist y=',y
         ENDDO
         PRINT*,'weiter mit Enter'
         READ*
         DO I= 0,-8,-1
           x = I
           y = (x**2 - x + 7) / (x**2 + 2)
           PRINT*,'für x=',x,' ist y=',y
         ENDDO
         PRINT*,'weiter mit Enter'
         READ*
         DO I= 12,-10,-2
           x = I
           y = (x**2 - x + 7) / (x**2 + 2)
           PRINT*,'für x=',x,' ist y=',y
         ENDDO
         END
 
         PROGRAM Kapitel_4_Aufgabe_2
         IMPLICIT NONE
         REAL x, y, Nenner
         INTEGER I
         DO I= -100,100,25
           x = I*0.01
           Nenner = 16.0*x**2 + 8*x - 3
   * Nenner 0 ?
           IF ( ABS( Nenner ) .LT. 0.00001 ) THEN
   * ja
             PRINT*,'Für x=',x,' wird der Nenner 0'
           ELSE
   * nein: Normalfall
             y = (  3.0*SIN(x)**3 + 4.0*COS(x)**3  )  /  Nenner
             PRINT*,'Für x=',x,' wird y=',y
           ENDIF
         ENDDO
         END
   -  99 -          Anhang D: Lösungen zu den Übungsaufgaben          -  99 -
 
         PROGRAM Kapitel_4_Aufgabe_3
         IMPLICIT NONE
         REAL x, x0, Kandidat
         INTEGER I
         Kandidat = 2.0
   * eine erste Näherung für 1 / Wurzel aus 2
         x0 = 0.4
         DO I = 1,5
   * x ist die verbesserte Näherung
           x = 0.5 * x0 * ( 3.0 - Kandidat * x0**2 )
   * aus neu mach alt
           x0 = x
         ENDDO
         PRINT*,'nach 5 Iterationen ist die Näherung für 1 / Wurzel 2:',x
         PRINT*,'Zur Kontrolle: 1 / SQRT(2)=',1.0 / SQRT(Kandidat)
         END
 
         PROGRAM Kapitel_4_Aufgabe_4
         IMPLICIT NONE
         REAL x, x0, A
         INTEGER I
         A = 3.0
   * eine erste Näherung für 1 / A
         x0 = 0.5
         DO I = 1,5
   * x ist die verbesserte Näherung
           x = x0 * ( 2.0 - A * x0 )
           PRINT*,'Iteration Nr.',I,' gibt x=',x
   * aus neu mach alt
           x0 = x
         ENDDO
         PRINT*,'nach 5 Iterationen ist die Näherung für 1 /',A,x
         PRINT*,'Zur Kontrolle: 1 /', A ,' =',1.0 / A
         END
 
         PROGRAM Kapitel_4_Aufgabe_5
   * Aufgabenstellung:
   *   Berechnung von n Fibonacci-Zahlen (hier n=15)
   *   Definition der Fibonacci-Zahlen:
   *       gegeben sind 2 ganze Zahlen als Anfangswerte;
   *       3. Zahl = 2. + 1.; 4. = 3. + 2.; usw.
   *   Nr.1 und 2 werden eingelesen (inneres WHILE mit nr als Zaehler)
   *   dies wird bel. wiederholt (äußeres WHILE(.TRUE.) mit l1 als Zähler
         IMPLICIT NONE
         INTEGER A,B,C, D,NR, N
         N=15
         D=0
         WHILE(.TRUE.)
           PRINT*,'bitte 1. und 2. Fibonacci-Zahl eingeben; Ende: Strg_z'
           READ*,A,B
   *       AT END,QUIT
   *       ohne diese Anweisung gibt Strg_z einen  Error - end of file
           D=D+1
           PRINT*,'DURCHGANG NR.',D
           NR=1
   * die ersten 2 Zahlen werden gesondert ausgegeben
           PRINT*,'Fibonacci-Zahl Nr.',NR,A
           NR=NR+1
           PRINT*,'Fibonacci-Zahl Nr.',NR,B
           NR=NR+1
   * AB NR=3 läuft die WHILE-Schleife
 
 
   - 100 -          Anhang D: Lösungen zu den Übungsaufgaben          - 100 -
 
           WHILE( NR .LE. N )
   * Zahl c ist Summe der beiden vohergehenden (b,a)
             C=A+B
             PRINT*,'Fibonacci-Zahl Nr.',nr,c
   * b rückt an den Platz von a
             A=B
   * c rückt an den Platz von b
             B=C
             NR=NR+1
           ENDWHILE
           PRINT*,'Ende des Durchlaufs von',n,' Fibonacci-Zahlen'
         ENDWHILE
         PRINT*,'Ende des Programms nach',d,' Durchgängen'
         END
 
         PROGRAM Kapitel_4_Aufgabe_6
   *  Erweiterung von Aufg. 5:
   *    bei jedem Durchlauf 1...n werden die Quotienten je 2
   *    aufeinander folgender Zahlen berechnet (Typ REAL!)
         IMPLICIT NONE
         INTEGER A,B,C, D,NR, N
         N=15
         D=0
           WHILE(.TRUE.)
           PRINT*,'bitte 1. und 2. Fibonacci-Zahl eingeben'
           READ*,A,B
           D=D+1
           PRINT*,'Durchgang Nr.',d
           NR=2
           WHILE(.TRUE.)
             IF(NR.GT.N) QUIT
             C=A+B
             PRINT*,'Quotient: Nr.',nr,'/ Nr.',nr-1,REAL(c)/REAL(b)
             A=B
             B=C
             NR=NR+1
           ENDWHILE
           PRINT*,'Ende eines Durchlaufs von',n,' Fibonacci-Zahlen'
         ENDWHILE
         PRINT*,'Ende des Programms nach',d,' Durchgängen'
         END
 
         PROGRAM Kapitel_4_Aufgabe_7
         IMPLICIT NONE
         REAL pn, pn_1, pn_2
         INTEGER n,Max_Paare
         Max_Paare = 10
   * setzen Anfangswerte p0, p1
         pn_2 = 0
         pn_1 = 0.5
         PRINT*,'Die Wahrscheinlichkeit, daß keiner seinen Partner zieht'
           PRINT*,'ist bei',1,' teilnehmenden Paar  :',0
           PRINT*,'ist bei',2,' teilnehmenden Paaren:',0.5
         DO n = 3, Max_Paare
   * x ist die verbesserte Näherung
           pn =  (n-1.0)/n * pn_1 + (1.0/n) * pn_2
           PRINT*,'ist bei',n,' teilnehmenden Paaren:',pn
   * aus neu mach alt
           pn_2 = pn_1
           pn_1 = pn
         ENDDO
         PRINT*,'Viel vergnügen bei der Party'
         END
   - 101 -          Anhang D: Lösungen zu den Übungsaufgaben          - 101 -
 
         PROGRAM Kapitel_4_Aufgabe_8
         IMPLICIT NONE
         INTEGER n, i,j,k, np,nn
         PRINT*,'bitte n eingeben (z.B. 5)'
         READ*,n
         PRINT*,'Tripel positiver Zahlen:'
         np = 0
         DO i=1,n
           DO j=1,n
             DO k=1,n
   * hier werden alle Tripel von Zahlen von 1 bis n erzeugt
               IF ( i+j+k .EQ. n ) THEN
                 np = np+1
                 PRINT*,'Tripel Nr.',np,' ist',i,j,k
               ENDIF
         ENDDO
         PRINT*,'Tripel nicht negativer Zahlen:'
         PRINT*,'weiter mit Enter'
         READ*
         nn = 0
         DO i=0,n
           DO j=0,n
             DO k=0,n
   * hier werden alle Tripel von Zahlen von 0 bis n erzeugt
               IF ( i+j+k .EQ. n ) THEN
                 nn = nn+1
                 PRINT*,'Tripel Nr.',nn,' ist',i,j,k
               ENDIF
         ENDDO
         PRINT*,'Insgesamt wurden',np + nn,' Tripel gefunden'
         END
 
         PROGRAM Kapitel_4_Aufgabe_9
         IMPLICIT NONE
         INTEGER i,j
         REAL x,y,z
         PRINT*,'z = (x**2 - 2*x*y + 3*y**3 ) / ( x*y + 3*x * 2*y + 4 ):'
         DO i=1,6
           x = i
           DO j=1,5
             y = j
             z = (x**2 - 2*x*y + 3*y**3 ) / ( x*y + 3*x * 2*y + 4 )
             PRINT*,'x=',x,' y=',y,' z=',z
           ENDDO
           PRINT*,'Weiter mit Enter'
           READ*
         ENDDO
         END
 
         PROGRAM Kapitel_4_Aufgabe_10
         IMPLICIT NONE
         INTEGER A,B, AA,BB, Summe
         A = 37
         B = 65
   *     PRINT*,'bitte 2 Zahlen eingeben'
   *     READ*,a,b
         AA = A
         BB = B
         Summe = B
 
 
 
 
   - 102 -          Anhang D: Lösungen zu den Übungsaufgaben          - 102 -
 
         WHILE ( AA .GT. 0 )
           AA = AA / 2
           BB = BB * 2
           IF ( MOD ( REAL(AA),2.0) .NE. 0 ) Summe = Summe + BB
         ENDWHILE
         PRINT*,'Das Produkt von',A,' und',B,' ist',Summe
         PRINT*,'Benutzt wurde nur die Division / Multiplikation mit 2 !!'
         END
 
         PROGRAM Kapitel_4_Aufgabe_11
         IMPLICIT NONE
         LOGICAL Tom, Dick, Zack, Frage1, Frage2, Frage3
         INTEGER i,j,k
         Tom  = .true.
         Dick = .true.
         Zack = .true.
         DO i=1,2
           DO j=1,2
             DO k=1,2
              Frage1 = Tom .EQV. Dick
              Frage2 = Dick .EQV. (Tom .EQV. Zack)
              Frage3 = Zack .EQV. Dick
              IF( Frage1 .AND. .NOT. Frage2 .AND. Frage3 )
        &      PRINT*,'Jetzt wird klar: Tom,Dick,Zack sind ',Tom,Dick,Zack
              Tom = .false.
             ENDDO
             Dick = .false.
           ENDDO
           Zack = .false.
         ENDDO
         END
 
         PROGRAM Kapitel_4_Aufgabe_12
         IMPLICIT NONE
         REAL x, E
         INTEGER I
   *     PRINT*,'Bitte Zahl eingeben'
   *     READ*,x
         x = 4059.26
         PRINT*,'x=',x
         E = x * 0.5
         DO I=1,8
           E = E - ( E**2 -x ) / ( 2*E )
           PRINT*,'Näherung Nr.',I,' :',E
         ENDDO
         PRINT*,'Zur Kontrolle: SQRT(x)=   ',SQRT(x)
         END
 
         PROGRAM Kapitel_4_Aufgabe_13
         IMPLICIT NONE
         REAL x, Eneu, Ealt, Genauigkeit
         INTEGER I, Max_Iter
   *     PRINT*,'Bitte Zahl eingeben'
   *     READ*,x
         x = 3.0
         PRINT*,'x=',x
   * setzen der Parameter für das Verfahren
         Max_Iter = 3
         Genauigkeit = 0.0001
   * setzen 1. Näherung
         Ealt = x * 0.5
 
 
   - 103 -          Anhang D: Lösungen zu den Übungsaufgaben          - 103 -
 
   * Algorithmus
         DO I=1,Max_Iter
           Eneu = Ealt - ( Ealt**2 -x ) / ( 2*Ealt )
           PRINT*,'Näherung Nr.',I,' :',Eneu
   * Abbruchkriterium
           IF ( ABS( Eneu - Ealt ) .LT. Genauigkeit ) QUIT
   * für den neuen Iterationsschritt wird das "alte" Eneu zu Ealt
           Ealt = Eneu
         ENDDO
   * ex post Analyse
         IF ( I .LE. Max_Iter ) THEN
           PRINT*,'Ende der Iteration mit Genauigkeit', Genauigkeit
         ELSE
           PRINT*,'Abbruch der Iteration nach',Max_Iter,' Schritten'
           PRINT*,'Genauigkeit', Genauigkeit,' wurde nicht erreicht'
         ENDIF
         PRINT*,'Zur Kontrolle: SQRT(x)=   ',SQRT(x)
         END
 
         PROGRAM Kapitel_5_Aufgabe_1
         IMPLICIT NONE
         INTEGER K(5), P(5), N(5), Z(5), i, np,nn,nz
         PRINT*,'bitte 5 Zahlen in einer Zeile eingeben'
         READ*,K
         np = 0
         nn = 0
         nz = 0
         DO i=1,5
           IF( K(i) .GT. 0 ) THEN
             np = np + 1
             P(np) = i
           ELSEIF( K(i) .LT. 0 ) THEN
             nn = nn + 1
             N(nn) = i
           ELSE
             nz = nz + 1
             Z(nz) = i
           ENDIF
         ENDDO
         PRINT*,'Werte:',K
         PRINT*,'Indizes der positiven Werte:',(P(i),i=1,np)
         PRINT*,'Indizes der negativen Werte:',(N(i),i=1,nn)
         PRINT*,'Indizes der zero      Werte:',(Z(i),i=1,nz)
         END
 
         PROGRAM Kapitel_5_Aufgabe_2
         IMPLICIT NONE
         INTEGER F(5), i ,j
         PRINT*,'bitte 5 Zahlen'
         READ*,F
         PRINT*,'Paare, deren Summe 12 ergibt:'
         DO i=1,4
           DO j=i+1,5
             IF (  F(i) + F(j) .EQ. 12 ) THEN
               PRINT*,F(i),F(j)
             ENDIF
         ENDDO
         END
 
 
 
 
 
   - 104 -          Anhang D: Lösungen zu den Übungsaufgaben          - 104 -
 
         PROGRAM Kapitel_5_Aufgabe_3
         IMPLICIT NONE
         INTEGER Alter(10), i,j, Differenz(10,10),
        &        max_i,max_j,min_i,min_j, max_diff, min_diff
         PRINT*,'bitte 10 Alterszahlen'
         READ*,Alter
         DO i=1,9
           DO j=i+1,10
             Differenz ( i,j ) = ABS ( Alter(i) - Alter(j) )
         ENDDO
         Max_Diff = -1
         Min_Diff = 999999
         DO i=1,10
           DO j=i+1,10
             IF (Differenz ( i,j ) .GT. Max_Diff ) THEN
               Max_Diff = Differenz ( i,j )
               max_i = i
               max_j = j
             ELSEIF (Differenz ( i,j ) .LT. Min_Diff ) THEN
               Min_Diff = Differenz ( i,j )
               min_i = i
               min_j = j
             ENDIF
         ENDDO
         PRINT*,'Die Personen mit maximal verschiedenem Alter sind:'
         PRINT*,'Personen Nr.',max_i,max_j,' im Alter von',
        &        Alter(max_i),Alter(max_j)
         PRINT*,'Die Personen mit minimal verschiedenem Alter sind:'
         PRINT*,'Personen Nr.',min_i,min_j,' im Alter von',
        &        Alter(min_i),Alter(min_j)
         END
 
         PROGRAM Kapitel_5_Aufgabe_4
         IMPLICIT NONE
         INTEGER A(8),B(8),i,j
   *     DATA A/2,5,8,4,7,1,6,10/,B/9,8,4,10,3,5,12,11/
   * bei Benutzung von DATA entfallen die nächsten 4 Anweisungen
         PRINT*,'bitte 8 Werte für A'
         READ*,(A(i),i=1,8)
         PRINT*,'bitte 8 Werte für B'
         READ*,(B(i),i=1,8)
   *
         PRINT*,'In A und B:'
         DO i=1,8
           DO j=1,8
             IF ( A(i) .EQ. B(j) ) PRINT*,A(i)
         ENDDO
         PRINT*,'Weiter mit Enter'
         READ*
         PRINT*,'In B, aber nicht in A:'
         DO i=1,8
           DO j=1,8
   * wenn auch nur eines der Aj gleich Bi ist: Schleife vorzeitig verlassen
             IF ( B(i) .EQ. A(j) ) GOTO 10
           ENDDO
   * hier wird die j-Schleife beendet, wenn alle Aj ungleich Bi sind
           PRINT*,B(i)
   10      CONTINUE
         ENDDO
         PRINT*,'Weiter mit Enter'
         READ*
 
 
   - 105 -          Anhang D: Lösungen zu den Übungsaufgaben          - 105 -
 
         PRINT*,'In A, aber nicht in B:'
         DO i=1,8
           DO j=1,8
   * wie oben, nur die Rolle von A und B vertauscht
             IF ( A(i) .EQ. B(j) ) GOTO 20
           ENDDO
   * hier wird die j-Schleife beendet, wenn alle Bj ungleich Ai sind
           PRINT*,A(i)
   20      CONTINUE
         ENDDO
         PRINT*,'Weiter mit Enter'
         READ*
   *
         PRINT*,'Entweder in A oder in B (aber nicht in beiden)'
         PRINT*,'Das sind alle Werte, die in A, aber nicht in B sind'
         PRINT*,'sowie alle Werte, die in B, aber nicht in A sind'
         PRINT*,'also die Vereinigungsmenge der beiden eben gezeigten Werte
        &mengen'
         END
 
         PROGRAM Kapitel_5_Aufgabe_5
   *    Erweiterung Kap. 4 Aufg. 8:
   *    Die n Fibonacci-Quotienten werden in ein Feld  gespeichert
   *    nach jedem Durchlauf 1...n werden die Quotienten
   *    Fibonacci(i+1) / Fibonacci(i) und   ...i / ...(i-1)
   *    in 2 Kolonnen ausgegeben
         IMPLICIT NONE
         INTEGER A,B,C, D,NR, N, I
         REAL Q(100)
         N=20
         D=0
         WHILE(.TRUE.)
           PRINT*,'bitte 1. und 2. Fibonacci-Zahl eingeben; Ende: Strg_z'
           READ*,A,B
   *       AT END,QUIT
   *       ohne diese Anweisung gibt Strg_z einen  Error - end of file
           D=D+1
           PRINT*,'Durchgang Nr.',d
           NR=2
           WHILE(.TRUE.)
             IF(NR.GT.N) QUIT
             C=A+B
             PRINT*,'Fibonacci-Zahl Nr.',nr,c
             Q(NR)=REAL(C)/REAL(B)
             A=B
             B=C
             NR=NR+1
           ENDWHILE
           PRINT*,'weiter mit Enter'
           READ*
           I=2
           PRINT*,'    Quotienten i / i-1                  i+1 / i'
           WHILE(.TRUE.)
             IF(I.GT.N-1) QUIT
             PRINT*,Q(I),Q(I+1)
             I=I+2
           ENDWHILE
           PRINT*,'Ende eines Durchlaufs von',n,' Fibonacci-Zahlen'
         ENDWHILE
         PRINT*,'Ende des Programms nach',d,' Durchgängen'
         END
 
 
   - 106 -          Anhang D: Lösungen zu den Übungsaufgaben          - 106 -
 
         PROGRAM Kapitel_5_Aufgabe_6
         IMPLICIT NONE
         INTEGER Temperaturen (4,7), Max(4), Min(4),
        &  Max_4_Wochen, Min_4_Wochen
         REAL Durchschnitt(4), Durchschnitt_4_Wochen
         INTEGER i,j
   * Eingabe
         DO i=1,4
           PRINT*,'bitte 7 Temperaturen für die',i,'. Woche'
           READ*, ( Temperaturen(i,j), j=1,7)
         ENDDO
   * Verarbeitung
         Durchschnitt_4_Wochen = 0
         Max_4_Wochen          = -273
         Min_4_Wochen          = 100
         DO i=1,4
           Durchschnitt(i) = 0
           Max(i)          = -273
           Min(i)          = 100
           DO j=1,7
             Durchschnitt(i) = Durchschnitt(i) + Temperaturen(i,j)
             IF ( Max(i) .LT. Temperaturen(i,j) )
        &         Max(i)  =   Temperaturen(i,j)
             IF ( Min(i) .GT. Temperaturen(i,j) )
        &         Min(i)  =   Temperaturen(i,j)
           ENDDO
           Durchschnitt(i) = Durchschnitt(i) / 7
           Durchschnitt_4_Wochen = Durchschnitt_4_Wochen + Durchschnitt(i)
           IF ( Max_4_Wochen .LT. Max(i) ) Max_4_Wochen = Max(i)
           IF ( Min_4_Wochen .GT. Min(i) ) Min_4_Wochen = Min(i)
         ENDDO
         Durchschnitt_4_Wochen = Durchschnitt_4_Wochen / 4
   * Ausgabe
         PRINT*,'                              Durch.      Max         Min'
         DO i=1,4
           PRINT*,'Woche ', I, Durchschnitt(i),Max(i),Min(i)
         ENDDO
         PRINT*,'                        ---------------------------------'
         PRINT*,'4-Wochen-Statistik:',
        &   Durchschnitt_4_Wochen, Max_4_Wochen, Min_4_Wochen
         END
 
         PROGRAM Kapitel_5_Aufgabe_7
         IMPLICIT NONE
         INTEGER Temperaturen (4,7),Max(4),Min(4),Max_Tag(7),Min_Tag(7),
        &        Max_4_Wochen, Min_4_Wochen
         REAL Durchschnitt(4), Durchschnitt_Tag(7), Durchschnitt_4_Wochen
         INTEGER i,j
   * Eingabe
         DO i=1,4
           PRINT*,'bitte 7 Temperaturen für die',i,'. Woche'
           READ*, ( Temperaturen(i,j), j=1,7)
         ENDDO
   * Verarbeitung
         Durchschnitt_4_Wochen = 0
         Max_4_Wochen          = -273
         Min_4_Wochen          = 100
 
 
 
 
 
 
   - 107 -          Anhang D: Lösungen zu den Übungsaufgaben          - 107 -
 
         DO i=1,4
           Durchschnitt(i) = 0
           Max(i) = -273
           Min(i) = 100
           DO j=1,7
             Durchschnitt(i) = Durchschnitt(i) + Temperaturen(i,j)
             IF ( Max(i) .LT. Temperaturen(i,j) )
        &         Max(i)  =   Temperaturen(i,j)
             IF ( Min(i) .GT. Temperaturen(i,j) )
        &         Min(i)  =   Temperaturen(i,j)
           ENDDO
           Durchschnitt(i) = Durchschnitt(i) / 7
           Durchschnitt_4_Wochen = Durchschnitt_4_Wochen + Durchschnitt(i)
         ENDDO
         Durchschnitt_4_Wochen = Durchschnitt_4_Wochen / 4
   * Durchschnitt, Max, Min für jeden Tag
         DO j=1,7
           Durchschnitt_Tag(j) = 0
           Max_Tag(j) = -253
           Min_Tag(j) = 100
           DO i=1,4
             Durchschnitt_Tag(j) = Durchschnitt_Tag(j) + Temperaturen(i,j)
             IF ( Max_Tag(j) .LT. Temperaturen(i,j) )
        &         Max_Tag(j)  =   Temperaturen(i,j)
             IF ( Min_Tag(j) .GT. Temperaturen(i,j) )
        &         Min_Tag(j)  =   Temperaturen(i,j)
             IF ( Max_4_Wochen .LT. Max(i) ) Max_4_Wochen = Max(i)
             IF ( Min_4_Wochen .GT. Min(i) ) Min_4_Wochen = Min(i)
           ENDDO
           Durchschnitt_Tag(j) = Durchschnitt_Tag(j) / 4
         ENDDO
   * Ausgabe
         PRINT*,'                            Durch.        Max         Min'
         DO i=1,4
           PRINT*,'Woche ', I, Durchschnitt(i),Max(i),Min(i)
         ENDDO
         PRINT*,'                        ---------------------------------'
         PRINT*,'4-Wochen-Statistik',
        &   Durchschnitt_4_Wochen, Max_4_Wochen, Min_4_Wochen
   * Ausgabe Tagesstatistik
         PRINT*
         PRINT*,'Tagesstatistik              Durch.        Max         Min'
         DO j=1,7
           PRINT*,'Tag', J, Durchschnitt_Tag(i),Max_Tag(i),Min_Tag(i)
         ENDDO
         PRINT*,'1=Mo, 2=Di, 3=Mi, 4=Do, 5=Fr, 6=Sa, 7=So'
         END
 
         PROGRAM Kapitel_6_Aufgabe_1
   * benötigt SUBROUTINE Umkehr
         IMPLICIT NONE
         INTEGER A(10)
         DATA A /1,2,3,4,5,6,7,8,9,10/
         PRINT*,'A:'
         PRINT*,A
         CALL Umkehr (A)
         PRINT*,'A umgedreht:'
         PRINT*,A
         END
 
 
 
 
   - 108 -          Anhang D: Lösungen zu den Übungsaufgaben          - 108 -
 
         SUBROUTINE Umkehr(V)
         IMPLICIT NONE
         INTEGER V(10),W(10),i
         DO i=1,10
           W(11-i) = V(i)
         ENDDO
         DO i=1,10
           V(i) = W(i)
         ENDDO
         END
 
         PROGRAM Kapitel_6_Aufgabe_2
   * benötigt FUNCTION Det
         IMPLICIT NONE
         REAL Testmatrix(2,2), Det
         DATA Testmatrix/ 1.0, 2.0, 3.0, 4.0 /
         PRINT*,'Die Determinante der Testmatrix ist', Det(Testmatrix)
         END
         REAL FUNCTION Det(X)
         IMPLICIT NONE
         REAL X(2,2)
         Det = X(1,1)*X(2,2) - X(2,1)*X(1,2)
         END
 
         PROGRAM Kapitel_6_Aufgabe_3
   * benötigt FUNCTION Det von Aufg. 2
         IMPLICIT NONE
         REAL A(2,2),Rechte_Seite(2), Loesung(2)
         INTEGER IFLAG
         DATA A/ 2., -4., 3., 8./, Rechte_Seite / 12.,4./
         CALL Cramer(A,Rechte_Seite,Loesung,IFlag)
   * Auswertung von IFLAG
         IF ( IFLAG .EQ. 0 ) THEN
             PRINT*,'unendlich viele Lösungen vorhanden'
         ELSEIF ( IFLAG .EQ. 2 ) THEN
             PRINT*,'keine Lösung vorhanden'
         ELSEIF ( IFLAG .EQ. 1 ) THEN
             PRINT*,'Die Lösung ist:', Loesung
         ELSE
             PRINT*,'ungültiger Wert von IFLAG!'
         ENDIF
         END
         SUBROUTINE Cramer(Koeff,RS,Loesung,IFLAG)
         IMPLICIT NONE
         REAL Koeff(2,2),RS(2),Loesung(2),Det_Koeff,Det_RSx,Det_RSy,Det
         INTEGER IFLAG
         Det_Koeff = Det(Koeff)
         Det_RSx   = RS(1)      * Koeff(2,2) - RS(2)      * Koeff(1,2)
         Det_RSy   = Koeff(1,1) * RS(2)      - Koeff(2,1) * RS(1)
         IF ( Det_Koeff .EQ. 0.0 ) THEN
           IF ( Det_RSx .EQ. 0.0 .OR. Det_RSy .EQ. 0.0 ) THEN
   *          unendlich viele Lösungen
             IFLAG = 2
           ELSE
   *         keine Lösungen
             IFLAG = 0
           ENDIF
         ELSE
           IFLAG = 1
           Loesung(1) = Det_RSx / Det_Koeff
           Loesung(2) = Det_RSy / Det_Koeff
         ENDIF
         END
   - 109 -          Anhang D: Lösungen zu den Übungsaufgaben          - 109 -
 
         PROGRAM Kapitel_6_Aufgabe_4
   * benötigt SUBROUTINE RANDI
         IMPLICIT NONE
         INTEGER Zufallsfeld(60),i,j
         Zufallsfeld(1) = 7**5
         CALL RANDI(Zufallsfeld,0,65535)
         DO i=0,59,6
           PRINT*,(Zufallsfeld(i+j),j=1,6)
         ENDDO
         END
   *
         SUBROUTINE RANDI(R,j,k)
         IMPLICIT NONE
         INTEGER R(60),j,k,n
         DO n=2,60
           R(n) = MOD ( 25173 * R(n-1),65536)
         ENDDO
         IF ( .NOT. (j.EQ.0 .AND. k.EQ.65536 ) ) THEN
   * nur falls nicht 0...65536 angegeben war: Zahlen umrechnen
           DO n=1,60
             R(n) = R(n) / 65535.0 * ( k-j+1 ) + j
           ENDDO
         ENDIF
         END
 
         PROGRAM Kapitel_6_Aufgabe_5
   * benötigt SUBROUTINE RANDI von Aufg. 4
         IMPLICIT NONE
         INTEGER Zufall(0:239),i,j,k,n,Wurf(6,6),Summe(2:12)
         DATA Wurf/36*0/,Summe/11*0/
   *             4 mal je 60 Zufallszahlen ...
         DO n=0,3
   *             1. Element wird "zufällig" auf 7**n gesetzt
           Zufall(60*n) = MOD( 7 ** n, 65536 )
           CALL RANDI(Zufall(60*n),1,6)
         ENDDO
   * 100 Würfe mit je 2 Würfeln: je 2 aufeinanderfolgende Zufallszahlen
         DO i=0,199,2
   * war der Wurf z.B. (6,6), so ergibt die folgende Anweisung:
   *       Wurf(     6   ,     6     ) = Wurf(     6   ,     6    ) + 1
           Wurf(Zufall(i),Zufall(i+1)) = Wurf(Zufall(i),Zufall(i+1)) + 1
         ENDDO
         PRINT*,'Tabelle der Wurfhäufigkeiten (i,j) = Element (i,j)'
         DO i=1,6
           PRINT*, (Wurf(i,j),j=1,6)
         ENDDO
   * Häufigkeiten der Würfe mit der Summe i+j = Element (i+j) von Summe'
         DO i=1,6
           DO j=1,6
             Summe (i+j) = Summe(i+j) + Wurf(i,j)
         ENDDO
         DO k=2,12
           PRINT*,'Rel.Häufigkeit der Würfe mit Summe',k,' =',Summe(k)/100.
         ENDDO
         END
 
         PROGRAM Kapitel_6_Aufgabe_6
   * benötigt SUBROUTINE Insert
         IMPLICIT NONE
         INTEGER Feld(20),I, Ins
         DATA Feld/20*999999/
   *                 -999999 wenn absteigend sortiert werden soll
         PRINT*,'Es sollen 20 Zahlen einsortiert werden'
   - 110 -          Anhang D: Lösungen zu den Übungsaufgaben          - 110 -
 
         DO i=1,20
         PRINT*,'bitte Zahl',i,'(max.6 Ziffern) zum Einsortieren angeben'
           READ, Ins
           CALL Insert(Feld,Ins)
         ENDDO
         PRINT*,'Die folgenden Werte müssen aufsteigend sein:'
         PRINT*,Feld
         END
 
         SUBROUTINE Insert(K,Ins)
         IMPLICIT NONE
         INTEGER K(20),Ins,n,i
   * vergleiche, bis Ins nicht mehr kleiner als die bereits sortierten Werte
         n = 1
         WHILE ( Ins .GT. K(n) .AND. n .LT. 20)
   *                 .LT.    würde absteigend sortieren
           n = n + 1
         ENDWHILE
   * Platz schaffen für das neue Element
         DO i=20,n+1,-1
           K(i) = K(i-1)
         ENDDO
   * da kommt es hin
         k(n) = Ins
         END
 
         PROGRAM Kapitel_6_Aufgabe_7
   * benötigt SUBROUTINEn : EINGABE,BERECHNE,AUSGABE; FUNCTIONs : UEBER,FAK
   * Aufgabenstellung: Pascalsches Dreieck          1
   *                                              1   1
   *                                            1   2   1
   *                                          1   3   3   1
   *                                        .   .   .   .   .
   *   Jede Zahl ergibt sich als Summe der Zahlen schräg rechts und links
   *                                              ( n )   ( n )      ( n )
   *   Zeile n enthält die Binomialkoeffizienten  ( 0 ) , ( 1 ) ,.., ( n )
   *   Definition der Binomialkoeffizienten ( a )      a !
   *                          a ueber b:    ( b ) =  --------------
   *                                                 b ! * ( a-b) !
   *   Die Summe in jeder Zeile ist 2**n    (1.Zeile soll n=0 haben)
   *   maximal 9. Ordnung;     es wird nur ganzzahlig gerechnet
   *   die Ausgabe erscheint in der Form  .
   *                                      .  .
   *                                      .  .  .   usw.
   *   da die symmetrische Dreiecksgestalt schwierig zu programmieren ist
   *   (Fortgeschrittene können es mit Hilfe von Formaten versuchen)
         IMPLICIT NONE
         INTEGER Anzahl, Zeile(11), Ordnung, Max_Ordnung
         PARAMETER ( Max_Ordnung = 10 )
         LOGICAL Ende /.FALSE./
         Anzahl = 0
   * Endlosschleife für mehrfache Eingabe
         WHILE(.TRUE.)
           CALL EINGABE(Ordnung,Max_Ordnung,Ende)
           IF ( Ende ) QUIT
   * die folgende Anweisung verläßt die Schleife (weiter hinter ENDWHILE)
           Anzahl = Anzahl +1
           CALL Berechne( Zeile,Ordnung)
         ENDWHILE
         PRINT*
         PRINT*,'es wurden',Anzahl,' Pascalsche Dreiecke erzeugt'
         PRINT*,'Ende des Programms Pascaldreieck'
         END
   - 111 -          Anhang D: Lösungen zu den Übungsaufgaben          - 111 -
 
         SUBROUTINE EINGABE (Ordnung, Max_Ordnung, Ende)
         IMPLICIT NONE
         LOGICAL Ende
         INTEGER Ordnung, Max_Ordnung
         PRINT*
         PRINT*,'bitte Ordnung des Pascalschen Dreiecks angeben'
         READ*, Ordnung
         IF(Ordnung.GT.Max_Ordnung) THEN
           PRINT*,'maximale Ordnung ist',Max_Ordnung
           Ordnung = Max_Ordnung
         ELSEIF(Ordnung .LT. 0) THEN
           Ende = .TRUE.
           RETURN
         ENDIF
         PRINT*,'Pascalsches Dreieck der Ordnung',Ordnung
         END
 
         SUBROUTINE BERECHNE (Zeile,Ordnung)
         IMPLICIT NONE
         INTEGER Zeile(11),Ordnung,UEBER,n,m
         PRINT*,'           1'
         DO n=1,Ordnung
           DO m=0,n
   * n ueber m: also  ( 1 )  ( 1 ) bis ( 1 ) ... (ordnung) ... (ordnung)
   *                  ( 0 )  ( 1 )     ( 0 )     (    0  )     (ordnung)
             Zeile(m+1)= UEBER(n,m)
           ENDDO
           CALL AUSGABE (Zeile,n+1)
         ENDDO
         END
 
         SUBROUTINE AUSGABE (Zeile,x)
         IMPLICIT NONE
         INTEGER Zeile(11),j,x
   *        WRITE(6,'(10I8)') ( Zeile(J),J=1,x)  besseres Druckbild!
           PRINT*, ( Zeile(J),J=1,x)
         END
 
         INTEGER FUNCTION UEBER (a,b)
   * berechnet a "über" b, dh.  a! / ( b! (a-b)! )
         IMPLICIT NONE
         INTEGER a,b, FAK
           UEBER = FAK(a) / ( FAK(b) * FAK(a-b) )
         END
         INTEGER FUNCTION FAK(n)
   * berechnet n! (n Fakultät)
         IMPLICIT NONE
         INTEGER n, m
         IF(n.LT.0) THEN
           PRINT*,'***ERROR*** N Fakultät für n=',n
           STOP
         ELSE
           FAK=1
           DO m=2,n
             FAK = FAK * m
           ENDDO
         ENDIF
         END
         PROGRAM Kapitel_6_Aufgabe_8
   * benötigt die SUBROUTINE Baue_Matrix
         IMPLICIT NONE
         INTEGER Max_n,Max_m,Max_nm,n,m,i,j
         PARAMETER ( Max_n = 6 , Max_m = 6, Max_nm = Max_n * Max_m )
   - 112 -          Anhang D: Lösungen zu den Übungsaufgaben          - 112 -
 
   * Eingabe
         INTEGER Matrix(Max_n,Max_m),Vektor(Max_nm)
         PRINT*,'bitte n und m eingeben'
         READ*,n,m
         IF ( n .GT. Max_n ) THEN
           PRINT*,'n ist maximal', Max_n
           n = Max_n
         ENDIF
         IF ( m .GT. Max_m ) THEN
           PRINT*,'m ist maximal', Max_m
           m = Max_m
         ENDIF
         PRINT*,'bitte', n * m, ' Werte eingeben'
         READ*, ( Vektor(i), i = 1, n*m )
   * Verarbeitung
         CALL Baue_Matrix ( Max_n, Max_n, n, m, Vektor, Matrix )
   * Ausgabe
         PRINT*,'Ausgabe der aufgebauten Matrix:'
         DO i=1,n
           PRINT*, ( Matrix ( i,j ), j=1,m )
         ENDDO
         END
   *
         SUBROUTINE Baue_Matrix ( d1, d2, a,b, X, Y )
   * Kapitel_6_Aufgabe_8
         IMPLICIT NONE
         INTEGER d1,d2, a,b, X(a*b), Y(d1,d2), n,i,j
         n = 0
         DO i=1,a
           DO j=1,b
             n = n + 1
             Y (i,j) = x(n)
         ENDDO
         END
 
         PROGRAM Kapitel_6_Aufgabe_9
   * benötigt die SUBROUTINE Merge
         IMPLICIT NONE
         INTEGER Max_m, Max_2m, m1,m2,i
         PARAMETER ( Max_m = 10, Max_2m = 2 * Max_m )
   * Eingabe
         INTEGER Menge1 (Max_m), Menge2 (Max_m), M12(Max_2m)
         PRINT*,'bitte m1 und m2 eingeben'
         READ*,m1,m2
         IF ( m1 .GT. Max_m ) THEN
           PRINT*,'m1 ist maximal', Max_m
           m1 = Max_m
         ENDIF
         IF ( m2 .GT. Max_m ) THEN
           PRINT*,'m2 ist maximal', Max_m
           m2 = Max_m
         ENDIF
         PRINT*,'bitte', m1, ' Werte eingeben'
         READ*, ( Menge1(i), i = 1, m1 )
         PRINT*,'bitte', m2, ' Werte eingeben'
         READ*, ( Menge2(i), i = 1, m2 )
   * Verarbeitung
         CALL Merge ( m1,m2, Menge1,Menge2, M12 )
   * Ausgabe
         PRINT*,'Ausgabe der gemergten Menge:'
         PRINT*, ( M12 ( i ), i=1,m1+m2 )
         END
 
   - 113 -          Anhang D: Lösungen zu den Übungsaufgaben          - 113 -
 
         SUBROUTINE Merge ( a,b, X,Y,Z )
         IMPLICIT NONE
         INTEGER a,b, X(a), Y(b), Z(a+b), i,j,k,n
         i = 1
         j = 1
         k = 1
         WHILE ( i .LE. a .AND. j .LE. b )
           IF ( X(i) .LE. Y(j) ) THEN
             Z(k) = X(i)
             i = i + 1
           ELSE
             Z(k) = Y(j)
             j = j + 1
           ENDIF
           k = k + 1
         ENDWHILE
         IF ( i .GT. a ) THEN
           DO n=j,b
             Z(k) = Y(n)
             k = k + 1
           ENDDO
         ELSEIF ( j .GT. b ) THEN
           DO n=i,a
             Z(k) = X(n)
             k = k + 1
           ENDDO
         ENDIF
         END
 
         PROGRAM Kapitel_7_Aufgabe_1
         IMPLICIT NONE
         REAL Temperatur (4,7),Durchschnitt(4),Max(4),Min(4),
        &  Durchschnitt_4_Wochen, Max_4_Wochen, Min_4_Wochen
         INTEGER i,j
   * Eingabe
         DO i=1,4
           PRINT*,'bitte 7 Temperatur für die',i,'. Woche'
           READ*, ( Temperatur(i,j), j=1,7)
         ENDDO
   * Verarbeitung
         Durchschnitt_4_Wochen = 0.0
         Max_4_Wochen          = 0.0
         Min_4_Wochen          = 0.0
         DO i=1,4
           Durchschnitt(i) = 0.0
           Max(i)          = -273.0
           Min(i)          = 100.0
           DO j=1,7
             Durchschnitt(i) = Durchschnitt(i) + Temperatur(i,j)
             IF ( Max(i) .LT. Temperatur(i,j) )
        &         Max(i)  =   Temperatur(i,j)
             IF ( Min(i) .GT. Temperatur(i,j) )
        &         Min(i)  =   Temperatur(i,j)
           ENDDO
           Durchschnitt(i) = Durchschnitt(i) / 7.0
           Durchschnitt_4_Wochen = Durchschnitt_4_Wochen + Durchschnitt(i)
           Max_4_Wochen          = Max_4_Wochen          + Max(i)
           Min_4_Wochen          = Min_4_Wochen          + Min(i)
         ENDDO
         Durchschnitt_4_Wochen = Durchschnitt_4_Wochen / 4.0
         Max_4_Wochen          = Max_4_Wochen          / 4.0
         Min_4_Wochen          = Min_4_Wochen          / 4.0
   * Ausgabe
   - 114 -          Anhang D: Lösungen zu den Übungsaufgaben          - 114 -
 
         PRINT*,'           Mo    Di    Mi    Do    Fr    Sa    So
        &Durch. Max   Min'
         DO i=1,4
           WRITE(6,'(A,I2,7F6.1,7X,3F6.1)') 'Woche', I,
        &  (Temperatur(i,j),j=1,7),Durchschnitt(i),Max(i),Min(i)
         ENDDO
         WRITE(6,'(58X,16(''-'')/ A, 38X ,3F6.1)') '4-Wochen-Statistik',
        &   Durchschnitt_4_Wochen, Max_4_Wochen, Min_4_Wochen
         END
 
         PROGRAM Kapitel_7_Aufgabe_2
         IMPLICIT NONE
         REAL Temperatur (4,7),Durchschnitt(4),Max(4),Min(4),
        &  Durchschnitt_4_Wochen, Max_4_Wochen, Min_4_Wochen
         REAL Durchschnitt_Tag(7),Max_Tag(7),Min_Tag(7)
         INTEGER i,j
   * Eingabe
         DO i=1,4
           PRINT*,'bitte 7 Temperatur für die',i,'. Woche'
           READ*, ( Temperatur(i,j), j=1,7)
         ENDDO
   * Verarbeitung
         Durchschnitt_4_Wochen = 0.0
         Max_4_Wochen          = 0.0
         Min_4_Wochen          = 0.0
         DO i=1,4
           Durchschnitt(i) = 0.0
           Max(i) = -273.0
           Min(i) = 100.0
           DO j=1,7
             Durchschnitt(i) = Durchschnitt(i) + Temperatur(i,j)
             IF ( Max(i) .LT. Temperatur(i,j) )
        &         Max(i)  =   Temperatur(i,j)
             IF ( Min(i) .GT. Temperatur(i,j) )
        &         Min(i)  =   Temperatur(i,j)
           ENDDO
           Durchschnitt(i) = Durchschnitt(i) / 7.0
           Durchschnitt_4_Wochen = Durchschnitt_4_Wochen + Durchschnitt(i)
           Max_4_Wochen          = Max_4_Wochen          + Max(i)
           Min_4_Wochen          = Min_4_Wochen          + Min(i)
         ENDDO
         Durchschnitt_4_Wochen = Durchschnitt_4_Wochen / 4.0
         Max_4_Wochen          = Max_4_Wochen          / 4.0
         Min_4_Wochen          = Min_4_Wochen          / 4.0
   * Durchschnitt, Max, Min für jeden Tag
         DO j=1,7
           Durchschnitt_Tag(j) = 0.0
           Max_Tag(j) = -253
           Min_Tag(j) = 100
           DO i=1,4
             Durchschnitt_Tag(j) = Durchschnitt_Tag(j) + Temperatur(i,j)
             IF ( Max_Tag(j).LT.Temperatur(i,j) )Max_Tag(j) = Temperatur(i,j)
             IF ( Min_Tag(j).GT.Temperatur(i,j) )Min_Tag(j) = Temperatur(i,j)
             ENDDO
           Durchschnitt_Tag(j) = Durchschnitt_Tag(j) / 7.0
           ENDDO
   * Ausgabe
         PRINT*,'           Mo    Di    Mi    Do    Fr    Sa    So
        &Durch. Max   Min'
         DO i=1,4
           WRITE(6,'(A,I2,7F6.1,7X,3F6.1)') 'Woche', I,
        &  (Temperatur(i,j),j=1,7),Durchschnitt(i),Max(i),Min(i)
         ENDDO
   - 115 -          Anhang D: Lösungen zu den Übungsaufgaben          - 115 -
 
         WRITE(6,'(58X,16(''-'')/ A, 38X ,3F6.1)') '4-Wochen-Statistik',
        &   Durchschnitt_4_Wochen, Max_4_Wochen, Min_4_Wochen
   * Ausgabe Tagesstatistik
         PRINT*
         PRINT*,'Tagesstatistik    Durch.  Max   Min'
         DO j=1,7
           WRITE(6,'(A,I2, 12X, 3F6.1)') 'Tag', J,
        &  Durchschnitt_Tag(j),Max_Tag(j),Min_Tag(j)
         ENDDO
         PRINT*,'1=Mo, 2=Di, 3=Mi, 4=Do, 5=Fr, 6=Sa, 7=So'
         END
 
         PROGRAM Kapitel_7_Aufgabe_3
   * benötigt die SUBROUTINE Merge von Kap. 6 Aufg. 9
         IMPLICIT NONE
         INTEGER Max_m, Max_km, Max_k, i,j,k,ii,l
         PARAMETER ( Max_m = 10, Max_k = 5, Max_km = Max_k * Max_m )
   * Eingabe
         INTEGER Menge(Max_m,Max_k), m(Max_k),
        &        Menge_gemerged_1(Max_km), Menge_gemerged_2(Max_km)
         PRINT*,'bitte Zahl der zu mergenden Mengen angeben ( >=2 ):'
         READ*,k
         IF ( k .GT. Max_k ) THEN
           PRINT*,'k ist maximal', Max_k
           k = Max_k
         ELSEIF ( k .LT. 2 ) THEN
           PRINT*,'k ist mindestens 2'
           k = 2
         ENDIF
         DO i=1,k
           WRITE(6,'(A,I1,A)') 'bitte m',i,' angeben'
           READ*,m(i)
           IF ( m(i) .GT. Max_m ) THEN
             WRITE(6,'(A,I1,A,I2)') 'm',i,' ist maximal', Max_m
             m(i) = Max_m
           ENDIF
           WRITE(6,'(A,I2,A)') 'bitte',m(i),' aufsteigend sortierte Werte
        &eingeben'
           READ*, ( Menge(j,i), j = 1, m(i) )
   * Verarbeitung
           IF ( i .EQ. 2 ) THEN
   * Merge die ersten beiden Mengen
             ii = m(1) + m(2)
             CALL Merge ( m(1),m(2),
        &               Menge(1,1), Menge(1,2), Menge_gemerged_1 )
           ELSEIF ( i .GT. 2 ) THEN
   * Merge eine weitere ( Menge(1,i) zu der bereits vorhandenen dazu
             CALL Merge ( ii, m(i),
        &               Menge_gemerged_1, Menge(1,i), Menge_gemerged_2)
   * die Länge der neuen Menge ist gleich der alten plus m(i)
             ii = ii + m(i)
   * die neu entstandene Menge wird an den Platz der alten abgespeichert
             DO l=1,ii
               Menge_gemerged_1(l) =  Menge_gemerged_2 (l)
             ENDDO
           ENDIF
         ENDDO
   * Ausgabe
         PRINT*,'Ausgabe der',k,' gemergten Mengen mit',ii,' Elementen:'
         PRINT*, ( Menge_gemerged_1 ( i ), i=1,ii)
         END
         SUBROUTINE Merge ( a,b, X,Y,Z )
   * s. oben Kapitel_6_Aufgabe_9
   - 116 -                           Index                            - 116 -
 
                                     Index
                                     ¯¯¯¯¯
   Die Zahlen geben die Seiten im Skript an, wo das entsprechende
   Stichwort nachzulesen ist.
 
   A-Code ... 73
   ACCESS= ... 24
   ADVANCE= ... 74
   Addition ... 11  20  27  81
   Algorithmus ... 12  16  17  19  28  35  38  40  49  51  52  53  55
   Anfangswert ... 34  36  39  41  43  46  85  87  88
   Anweisung, ausführbare ... 87  88
   Anweisungs-Teil ... 18
   Anweisungsfeld ... 10
   Anweisungsnummer ... 10  62
   Argument ... 25  50  51  52  53  57  61  88
   Argumenten-Liste ... 50  61  88
   Arithmetik ... 11  20  21  26
   Arithmetik, gemischte ... 21
   ASA-Drucksteuerzeichen ... 70
   ASCII-Code ... 79
   Aufruf, Wirkungsweise ... 61
   Aufruf einer Subroutine ... 50  51  88
   Ausdruck, arithmetischer ... 88
   Ausdruck, logischer ... 28  29  31  32  34  87  88
   Ausführen des Programms ... 05  07
   Ausführungszeit ... 59
   Ausgabe von Integer-Zahlen ... 68  72
   Ausgabe von Real-Zahlen ... 71
   Ausgabe-Element ... 67  76
   Ausgabe-Gerät ... 67
   Ausgabe, formatfreie ... 67  68  87
   Ausgabe, formatierte ... 67  68  75
   Ausgabeposition ... 69
   Ausgabeposition, implizite Angabe ... 70
   Ausgang aus der Schleife ... 48
   Auslöschung ... 27
   Ausnahmebedingung ... 38
 
   Bedingung ... 13  28  30  32  34  35  37  40  48  87  88
   Bibliothekskonzept ... 57
   blank ... 10  69  71  72  73  75  76  77
   Block-IF ... 28  29  31
   BN-Code ... 73  75
   BZ-Code ... 73  75
 
   CALL-Anweisung ... 51
   CASE-Anweisung ... 57
   Character-Ausdruck ... 78  88
   Character-Operator ... 78  88
   Character-String ... 10  25
   Character-Variable ... 76  78
   Character-Werte ... 78
   compile time ... 12  17  18
   compile time error ... 12  14
   Compiler ... 12  14  15  17  18  21  22  34  36  42  57  69  73  90
   CONTINUE-Anweisung ... 64  65
   Cursor ... 09  14  73  75  86
   D-Code ... 71  72
   DATA-Anweisung ... 46  73
   Datenende ... 64
   Debugger ... 18  90
 
   - 117 -                           Index                            - 117 -
 
   Deklaration ... 13  18  21  22  46  50  57  59  61  85  87  88
   Deklaration, explizite ... 22
   Deklaration von Konstanten ... 57
   Deklarations-Liste ... 87  88
   Deklarations-Teil ... 18
   Dezimalpunkt ... 13  14  17  20  63  67  72  73  88
   Dezimalsystem ... 26
   Dezimalzahl ... 14  17  26  40
   Dimensionierung ... 41  45  46  52  59  60  61  65
   Dimensionierung zur Ausführungszeit ... 59
   Dimensions-Liste ... 87  88
   Division ... 11  12  15  20  21  25  27  28  33  36  38  40
   Division durch 0 ... 12  15  28  36
   Division, ganzzahlige ... 20
   Divisionsrest ... 20  25
   DO-Anweisung ... 35  36
   DO-Block ... 36
   DO-Schleife ...
     35  36  37  39  40  41  43  45  46  60  61  64  67  75  81  88
   DO-Schleife, implizite ... 43  64  67
   DO-Schleifen-Steuergröße ... 61
   DO-Parameter ... 36
   DO-Variable ... 36  65
 
   E-Code ... 71  72
   E/A-Anweisung ... 73  82  88
   E/A-Befehl ... 75  76
   E/A-Befehl, neuer ... 75
   E/A-Einheit ... 88
   E/A-Gerät ... 63  90
   E/A-Liste ... 63  64  73  75  87  88
   EBCDI-Code ... 79
   Editieren ... 07  15  24
   Editor ... 07  08  09  90
   Ein- und Ausgabe ... 07  08  09  11  24  43  63  67  76  90
   Eingabe-Datenelement ... 63  64  76
   Eingabe-Gerät ... 63
   Eingabe-Liste ... 23  64  76
   Eingabe, formatfreie ... 63  64  66  87
   Eingabe, formatierte ... 63  66
   Einlesen einer unbekannten Anzahl von Daten ... 64
   END= ... 56  57  64  65
   END-Anweisung ... 50  51
   End-Of-File ... 64
   Endebedingung ... 48  87
   Endebedingungen, mehrere ... 37
   Endlosschleife ... 08  34  39  57
   Endwert ... 36  43  46  88
   Entscheidung ... 11  28
   ERR= ... 64
   error ... 08  12  17  18  64  74
   Erste-Buchstaben-Regel ... 22  60
   executable statement ... 18
   execution time ... 12  17  18
   execution time error ... 15  18
   EXIT-Anweisung ... 48
   Exponent ... 19  20  21  25  63  67  71  72  73  88
   Exponentenbereich ... 21
   Exponentialfunktion ... 25
   Exponentiation ... 20  88
   extension ... 09  18
   EXTERNAL-Deklaration ... 60  61
 
   - 118 -                           Index                            - 118 -
 
   Feld, Ein- und Ausgabe ... 43
   F-Code ... 71  72
   Fehlermeldung ... 12  14  15  18  42  65
   Fehlerquellen ... 26
   Feld, eindimensionales ... 41
   Feld, gerufenes ... 61
   Feld, höher dimensioniertes ... 45
   Feld, übergebenes ... 61
   Feld, 2-dimensional ... 43
   Feldelement ... 41  42  44  46  61  62  67  79  83  88
   Feldname ... 42  45  46  88
   Feldvariable ... 62  67
   File ... 07  08  09  24
   File, Ausdrucken ... 09
   File, internes ... 82
   Filehandling ... 09
   Filename ... 70
   Filename, Erweiterung ... 07
   FMT= ... 64  66  68  70  71  72
   FORMAT-Anweisung ... 63  66  67  68  69  88
   Formatcode ... 69  72  74  75  76  77  83  86  87  88
   Formatcode, autonomer ... 75
   Formatcode, beschreibender ... 75
   Format-Codes ... 85
   Formate, Regeln ... 75
   formatfrei ... 63  64  66  67  68  87
   formatiert ... 07  63  66  67  68  73  75  83
   Formatinfo ... 63  64  66  68
   Formatnummer ... 10  62
   Formatsteuerung ... 66
   Fortran-Anweisung ... 10  14  15  63  67
   Fortran-Namen ... 18  22
   Fortran-Standard ... 09  22
   Fortran-Standard-Erweiterung ... 81
   Fortran-Typ ... 17  87
   Fortran-Programm ... 09  10  12  18  50  51  62
   Fortran90-Standard ... 09  18  22  24  34  36  40  48  57  74  81  89
   Fortsetzungsspalte ... 10
   FUNCTION-Anweisung ...  50  87
   Function-Name ... 62
   Function-Unterprogramm ... 54
   Funktion, eingebaute ... 25  79  80
   Funktion, numerische ... 25  88
   Funktion, trigonometrische ... 25
   Funktionen ...
     18  20  25  32  50  54  55  57  60  61  62  78  79  81  84  88
   Funktionsnamen ... 50  54  57  61  87
   Funktionsnamen-Liste ... 87
   Funktionsaufruf ... 54
   Funktionswert ... 47  54  61  62  79  83  86
 
   G-Code ... 72  73
   Genauigkeit ... 11  22  26  27  71
   Geräte-Nr. ... 24  67  82  83  87
   gerundet ... 77
   global ... 62
   GOTO-Anweisung ... 28
   Hauptprogramm ... 50  51  53  58  59  60  62  75  87
   Hauptprogrammstruktur ... 58  87
 
 
 
 
   - 119 -                           Index                            - 119 -
 
   I-Code ... 68  69  72  73  79
   IBM-Compiler ... 36
   IBM-Großrechner ... 70  79
   IEEE-Standard ... 21
   IF-Anweisung ... 26  28
   IF-Block ... 28  29  30  31
   Index ... 25  41  42  43  44  45  46  47  79  80  81  85  86
   Indexgrenze, untere ... 45
   Integer-Ausdruck ...20  42
   Integer-Konstante ... 22  88
   Integer-Variable ...  22
   Integer-Zahl ... 20  21  22 68  69  70  72
   IMPLICIT NONE ... 22
   iterative Berechnung ... 16
 
   Klammerebene ... 74
   Klammer ... 20  32  34  40  41  50  74  88
   Kommentar ... 10  12  15  17  18  49  57  81  82  87
   Konkatenierung ... 78  79  88
 
   L-Code ... 73
   Leerelement ... 64
   Leerzeichen ...
     07  10  17  23  43  49  64  68  69  70  78  79  80  81  82  88
   Listing ... 08  09  12  15  24  90
   Listing-File ... 08  09  15  24
   Logarithmus ... 25  27
   Logical-Konstante ... 88
   lokal ... 18  57  62  85
 
   Maschinensprache ... 12  17
   Max-Dimension ... 88
   Meldungen ... 08  09  12  18
   Modul ... 57
   MS/DOS ... 07
   Multiplikation ... 11  20  27  37  40
 
   Name, Gültigkeitsbereich ... 57  62
   Name des Programms ... 12
   Namen der eingebauten Funktionen ... 62
   Namen, globale ... 62
   Namen, lokale ... 62
   Netzwerk-Drucker ... 09
   nicht (log. Operator) ... 32
   Normal-Record ... 76
   Nullelement ... 64
   Nummernfeld ... 10
 
   oder (log. Operator) ... 32
   oder, exklusives ... 30
   OPEN-Anweisung ... 24  70
   Operation, arithmetische ... 11  32
   Operator, arithmetischer ... 88
   Operator, logischer ... 28  32  88
 
   P-Code ... 73
   PARAMETER-Anweisung ... 57  65
   Parameter ... 50  51  53  54  57  58
   Parameter-Liste ... 50  57  60  61  87  88
   Polymorphismus ... 25
   PRINT-Anweisung ... 12  16  19  67
   Priorität ... 20  21  28  32
 
   - 120 -                           Index                            - 120 -
 
   privat ... 57
   Problem ... 11  12  17  38  41  46  48  58  82
   Programm, rufendes ... 51  57  76
   Programmbibliothek ... 57
   PROGRAM-Anweisung ... 51
   Programm-Kopf ... 12
   Programmablauf ... 28
   Programmlisting ... 05  07  08
   Programmname ... 07  08  87  90
 
   Quellprogramm ... 08  12
   QUIT-Anweisung ... 40  48
 
   READ-Anweisung ... 21  23  63  64  66  75
   Real-Ausdruck ... 42  78
   Real-Division ... 21
   Real-Grundrechenarten ... 21
   Real-Konstante ... 22  71  88
   Real-Variable ... 41
   Real-Zahl ... 15  20  21  26  71  72
   Real-Zahl, ganzzahliger Teil ... 21
   Real-Zahl, gebrochener Teil ... 21
   Record ... 73  75  82
   Record, neuer ... 73  75  83  88
   Recordlänge ... 76
   RETURN-Anweisung ... 51
 
   S-Code ... 73  75
   Schachtelung ... 30
   Schleife, regulärer Ausgang ... 48
   Schleife, zweiter Ausgang ... 48
   Schleifensteuerung ... 34  35  38  48
   Schnelldrucker ... 11  70
   Schnittstelle ... 57
   Schrittweite ... 36  43  84  87  88
   SELECT-Anweisung ... 57
   Skalenfaktor ... 73
   Sortieren ... 79
   SP-Code ... 73  75
   SS-Code ... 73  75
   Standard-Ausgabe ... 67  68  76
   Standard-Eingabe ... 63  66
   Standard-Einheit ... 63  64  68
   Standard-Funktions-Name ... 62
   Steueranweisung ... 28
   Steuerung ... 28  34  35  38  48  66  67  73
   STOP-Anweisung ... 36  51
   String ... 10  21  68  73  76  78  79
   String-Konstante ... 75  88
   Stringverarbeitung ... 25  78  79  81
   strukturiert ... 48
   SUBROUTINE-Anweisung ... 50  87
   Subroutine-Name ... 62
   Subroutine-Unterprogramm ... 50
   Substring ... 78  79  88
   Subtraktion ... 11  20  27
   Syntax-Fehler ... 14  17  18
 
   T-Code ... 69  73  75
   Tabulator ... 09  73  75  88
   Text ... 10  18  67
   trace ... 90
 
   - 121 -                           Index                            - 121 -
 
   traceback ... 15  90
   Typ CHARACTER ... 18  66  73  78  79  82  87
   Typ COMPLEX ... 17  25  87
   Typ INTEGER ... 17  36  42  67  73  87
   Typ LOGICAL ... 18  48  73  87
   Typ REAL ... 13  17  46  87
   Typ REAL*8 ... 22  87
   Typen, Voreinstellung ... 22
   Typ-Deklaration ... 21  46
   Typ-Umwandlungen ... 25
 
   Umlenken der Standard-Ein/Ausgabe ... 24
   und (log. Operator) ... 32
   undefinierter Wert, Ausgabe ... 15
   undefinierter Wert, Rechnen ... 15
   Unit ... 24  64  68  79  82  84  86  87  90
   UNIT= ... 24  64  68  79  82  84  86  87
   Unterprogramm, externes ... 60  61
   Unterprogramm, öffentlicher Teil ... 57
   Unterprogramm, privater Teil ... 57
   Unterprogramm-Namen ... 62
   Unterprogrammeinheit ... 57
   Unterprogrammstruktur ... 87
   UProg-Liste ... 61
 
   Variable, einfache ... 62
   Variablen-Liste ... 64  66  68
   Vektor ... 41  46  57  58  59  62
   Vergleichs-Operator ... 14  28  32  88
   von:bis ... 57  78  88  90
 
   warning ... 18
   WATFOR ... 07  08  09  12  18  22  24  90
   WEDIT ... 07
   Werte, Übergabe ... 61
   Werte-Liste ... 87  88
   WHILE-Anweisung ... 13  18  34
   WHILE-Schleife ... 34  35  87  88
   Wiederholungsfaktor ... 46  64  72  74  75  88
   Workspace ... 07  08  09
   Workstation ... 21  26  79
   WRITE-Anweisung ... 67  68  75  82
 
   X-Code ... 69  73  75
 
   Z-Code ... 73
   Zahl, ganze ... 17  20  26
   Zahl, komplexe ... 17  25  72
   Zahl mit Dezimalpunkt ... 13  20
   Zahlenbereich ... 20  68  71
   Zeichenkette ... 78
   Zuweisung von Werten ... 22
 
   : ... 73  75
   / ... 73  75
   $ ... 74  75
 
 
 
 
 
 
 
     SSSSSSSS    KK        KK  RRRRRRRRRR    IIIIIIII  PPPPPPPPP    TTTTTTTT
    SSSSSSSSSS   KK       KK   RRRRRRRRRRR   IIIIIIII  PPPPPPPPPP   TTTTTTTT
   SS        SS  KK      KK    RR        RR     II     PP       PP     TT
   SS            KK     KK     RR        RR     II     PP       PP     TT
    SSS          KK    KK      RR        RR     II     PP       PP     TT
      SSSS       KKKKKKK       RRRRRRRRRRR      II     PPPPPPPPPP      TT
        SSSS     KKKKKKK       RRRRRRRRRR       II     PPPPPPPPP       TT
           SSS   KK    KK      RR    RR         II     PP              TT
             SS  KK     KK     RR     RR        II     PP              TT
   SS        SS  KK      KK    RR      RR       II     PP              TT
    SSSSSSSSSS   KK       KK   RR       RR   IIIIIIII  PP              TT
     SSSSSSSS    KK        KK  RR        RR  IIIIIIII  PP              TT
 
                               ZZZZZZZZZZZZ  UU        UU
                               ZZZZZZZZZZZZ  UU        UU
                                       ZZZ   UU        UU
                                      ZZZ    UU        UU
                                     ZZZ     UU        UU
                                    ZZZ      UU        UU
                                   ZZZ       UU        UU
                                  ZZZ        UU        UU
                                 ZZZ         UU        UU
                                ZZZ          UU        UU
                               ZZZZZZZZZZZZ   UUUUUUUUUU
                               ZZZZZZZZZZZZ    UUUUUUUU
 
   FFFFFFFF   OOOOOOOO   RRRRRRRR  TTTTTTTT RRRRRRRR      AAAAAA    NN     NN
   FFFFFFFF  OOOOOOOOOO  RRRRRRRRR TTTTTTTT RRRRRRRRR    AAAAAAAA   NN     NN
   FF        OO      OO  RR      RR   TT    RR      RR  AA      AA  NNN    NN
   FF        OO      OO  RR      RR   TT    RR      RR  AA      AA  NNNN   NN
   FF        OO      OO  RR      RR   TT    RR      RR  AA      AA  NN NN  NN
   FFFFFFFF  OO      OO  RRRRRRRRR    TT    RRRRRRRRR   AAAAAAAAAA  NN NN  NN
   FFFFFFFF  OO      OO  RRRRRRRR     TT    RRRRRRRR    AAAAAAAAAA  NN  NN NN
   FF        OO      OO  RR  RR       TT    RR  RR      AA      AA  NN  NN NN
   FF        OO      OO  RR   RR      TT    RR   RR     AA      AA  NN   NNNN
   FF        OO      OO  RR    RR     TT    RR    RR    AA      AA  NN    NNN
   FF        OOOOOOOOOO  RR     RR    TT    RR     RR   AA      AA  NN     NN
   FF         OOOOOOOO   RR      RR   TT    RR      RR  AA      AA  NN     NN
 
                                                    777777777     777777777
                                                   77777777777   77777777777
                                                            777           777
                                                           777           777
                                                          777           777
                                                      7777777       7777777
                                                       777           777
                                                      777           777
                                                     777           777
                                                    777           777
                                                   777           777
                                                  777           777
 
                               444              //   99999999     777777777
                              4444             ///  9999999999   77777777777
                             44 44            ///  999      999           777
                            44  44           ///   99        99          777
                           44   44          ///    999      999         777
                          44    44         ///     99999999999      7777777
                          444444444444    ///         999999999      777
                          444444444444   ///                 99     777
                                44      ///                  99    777
                                44     ///         99        99   777
                              444444  ///           9999999999   777
                              444444  //             99999999   777
                                    © S.Vetter URZ Heidelberg 1986,1994,1997

Verantwortlich für den Inhalt: Siegfried Vetter
Datum der letzten Änderung: 25.03.1997