{
 Programm: Komplexe Zahlen; Berechnungen
 Autor   : Lampacher Martin
 Klasse  : 3Ib
 Datum   : 09/05/05
 Auftrag : Prof. Grazioli
}
PROGRAM czahlen;
USES
 Crt;
TYPE
 {
  Die Wahl fiel auf einen Record, weil
  jede komplexe Zahl aus einem Realteil und
  einem Imaginärteil besteht
 }
 Czahl = RECORD
  re : REAL;
  im : REAL;
 END;

{
 Prozedur : Gibt die Komplexe Zahl c aus
 Eingabep.: c, eine Komplexe Zahl
}
PROCEDURE Caus(c : Czahl);
 BEGIN
  {
   Diese Prozedur gibt nur das nötigste aus.
   Wenn also eine Komplexe Zahl komplett Null
   wird (oder der Real- bzw. Imaginärteil), dann
   schreibt sie auch nur das an. Bei kleinsten Kommastellen
   wird aber doch noch 0.00 ausgegeben
  }
  IF (c.re = 0) THEN
   BEGIN
    IF (c.im = 0) THEN
     WriteLn ('0')
    ELSE
     WriteLn (c.im:4:2,'i');
   END
  ELSE
   IF (c.im = 0) THEN
    WriteLn (c.re:4:2)
   ELSE
    IF (c.im > 0) THEN
     WriteLn (c.re:4:2,' +',c.im:4:2,'i')
    ELSE
     WriteLn (c.re:4:2,'  ',c.im:4:2,'i');
 END;

{
 Funktion : Wandelt den Imaginärteil der komplexen
            Zahl c in ihr Komplement um und gibt es
            zurück
 Eingabep.: c, eine Komplexe Zahl
 Rückgabe : das Komplement des Imaginaerteils
}
FUNCTION Ccon(c: czahl) : REAL;
 BEGIN
  c.im := (-1) * c.im;
  Ccon := c.im;
 END;

{
 Prozedur : Addiert die Komplexen Zahlen c1
            und c2 und speichert das Ergebnis
            in erg
 Eingabep.: c1, c2: Komplexe Zahlen
 Ausgabep.: erg, Ergebnis von c1+c2
}
PROCEDURE Cadd(    c1,c2 : Czahl;
               VAR erg   : Czahl);
 BEGIN
  erg.re := c1.re + c2.re;
  erg.im := c1.im + c2.im;
 END;

{
 Prozedur : Subtrahiert die Komplexen Zahlen c1
            und c2 und speichert das Ergebnis
            in erg
 Eingabep.: c1, c2: Komplexe Zahlen
 Ausgabep.: erg, Ergebnis von c1-c2
}
PROCEDURE Csub(    c1,c2 : Czahl;
               VAR erg   : Czahl);
 BEGIN
  erg.re := c1.re - c2.re;
  erg.im := c1.im - c2.im;
 END;

{
 Prozedur : Multipliziert die Komplexen Zahlen c1
            und c2 und speichert das Ergebnis
            in erg
 Eingabep.: c1, c2: Komplexe Zahlen
 Ausgabep.: erg, Ergebnis von c1*c2
}
PROCEDURE Cmal(    c1,c2 : Czahl;
               VAR erg   : Czahl);
 BEGIN
  erg.re := (c1.re * c2.re) + (c1.im * c2.im * (-1));
  erg.im := (c1.re * c2.im) + (c1.im * c2.re);
 END;

{
 Prozedur : Dividiert die Komplexen Zahlen c1
            und c2 und speichert das Ergebnis
            in erg
 Eingabep.: c1, c2: Komplexe Zahlen
 Ausgabep.: erg, Ergebnis von c1/c2
}
PROCEDURE Cdiv(    c1,c2 : Czahl;
               VAR erg   : Czahl);
 VAR
  c2komp, zaehler, nenner : Czahl;
 BEGIN
  c2komp.im := c2.im * (-1);
  c2komp.re := c2.re;
  Cmal(c1,c2komp,zaehler);
  Cmal(c2,c2komp,nenner );
  IF (nenner.re <> 0) THEN
   BEGIN
    erg.re := zaehler.re / nenner.re;
    erg.im := zaehler.im / nenner.re;
   END
  ELSE
   {
    Da eine Division durch Null nicht möglich
    ist, wird sie hier abgefragt
   }
   BEGIN
    WriteLn ('Division durch Null nicht möglich!');
    WriteLn ('Ergebnis erhält jetzt den Wert 0');
    erg.re := 0;
    erg.im := 0;
   END
 END;

{
 Prozedur : Wandelt den Radius r und den Winkel
            phi einer komplexen Zahl in der Polarform
            in eine Komplexe Zahl in karthesischer Form
 Eingabep.: r : Reelle Zahl, ist der Radius
            phi : Reelle Zahl, ist der Winkel im Bogenmaß
 Ausgabep.: c, eine komplexe Zahl in karthesischer Form
}
PROCEDURE Convert2karth(    r : REAL;
                            phi : REAL;
                        VAR c : Czahl);
BEGIN
 c.re := r * COS(phi);
 c.im := r * SIN(phi);
END;

{
 Prozedur : Wandelt eine komplexe Zahl in karthesischer Form
            in den Radius und den Winkel der Polarform um.
            Der Winkel wird in Radianten weitergegeben!
 Eingabep.: c, komplexe Zahl
 Ausgabep.: r : Reelle Zahl, Radius
            phi : Reelle Zahl, Winkel
}
PROCEDURE Convert2Polar(    c : Czahl;
                        VAR r : REAL;
                        VAR phi : REAL);
 VAR
  phi1 : REAL;
 BEGIN
  r := Sqrt(Sqr(Abs(c.re))+Sqr(Abs(c.im)));
  {
   Hier wird geprüft, ob ein Realteil vorhanden ist.
   Ist er null, darf die Formel phi = Arctan(|c.im/c.re|)
   nicht angewandt werden (Division durch Null)
  }
  IF (c.re = 0) THEN
   IF (c.im < 0) THEN
    phi := (270 * PI) / 180
   ELSE
    IF (c.im > 0) THEN
     phi := PI / 2
    ELSE
     phi := 0
  ELSE {Realteil nicht Null!}
   {
    Hier ist der Realteil nicht Null. Überprüfung,
    in welchen Quadranten wir uns befinden
   }
   IF (c.re < 0) THEN
    IF (c.im < 0) THEN                                   {--> III. Quadrant     }
     phi := PI + (Arctan(Abs(c.im) / Abs(c.re)))
    ELSE
     IF (c.im > 0) THEN                                  {--> II.  Quadrant     }
      phi := PI - (Arctan(Abs(c.im) / Abs(c.re)))
     ELSE                                                {--> nur eine neg. Zahl}
      phi := 180
   ELSE
    IF (c.im < 0) THEN                                   {--> IV.  Quadrant     }
     phi := 2*PI - Abs((Arctan(Abs(c.im) / Abs(c.re))))
    ELSE
     IF (c.im > 0) THEN                                  {--> I.   Quadrant     }
      phi := Arctan(Abs(c.im) / Abs(c.re))
     ELSE                                                {--> positive, R-Zahl  }
      phi := 0;
 END;

{
 Funktion : Potenziert die Basis basis
            um die Potenz n (rekursiv). Wird in
            Cpot verwendet (Potenzieren des Radius)
 Eingabep.: basis : Reelle Zahl
            n : Integerzahl
 Rückgabe : Ergebnis von basis^n in Real
}
FUNCTION Pot(n     : INTEGER;
             basis : REAL) : REAL;
 BEGIN
  IF n = 0 THEN
   Pot := 1  {Bei basis^0 wissen wir das Ergebnis: 1}
  ELSE
   Pot := basis * Pot(n-1,basis);
 END;

{
 Prozedur : Potenziert die komlexe Zahl c
            mit n, speichern in erg
 Eingabep.: c : Komplexe Zahl
            n : Integerzahl
 Ausgabep.: erg, Ergebnis von c^n
}
PROCEDURE Cpot(    n : INTEGER;
                   c : Czahl;
               VAR erg : Czahl);
 VAR
  r, phi : REAL;
 BEGIN
  IF (n >= 0) THEN
   BEGIN
    Convert2Polar(c,r,phi);         {Ich potenziere in der Polarform,   }
    r := Pot(n,r);                  {weil das einfacher zu handhaben ist}
    phi := n * phi;                 {Das Ergebnis wird aber in der Karth}
    Convert2karth(r,phi,erg);       {Form wieder zurückgegeben          }
   END
  ELSE   {Mit diesem Rechner kann man keine negativen Potenzen berechnen}
   BEGIN
    TextColor(19);
    WriteLn ('FEHLEINGABE!');
    WriteLn ('Negative Hochzahlen werden nicht akzeptiert!');
    WriteLn;
   END;
 END;

{
 Prozedur : Zieht die n-te Wurzel aus c,
            gibt die Ergebnisse aus
 Eingabep.: c : Komplexe Zahl
            n : Integerzahl
 Ausgabep.: erg, Ergebnis von n-te Wurzel aus c
}
PROCEDURE Crad(    n : INTEGER;
                   c : Czahl);
 VAR
  {
   Variablenerklärung:
    k = Laufvariable für Formel der Winkelberechnung
    r = Radius (verändert sich in der Ausgabe nie)
    phi = Hauptwert des Winkels
    phigrad = Zum Berechnen, im GRAD-Maß
    phirad  = Zum Berechnen, im RAD -Maß
    zw = Zwischenvariable
    cz = Zwischenvariable zum Berechnen, damit nicht
         c in Convert2karth als VAR übergeben wird, was
         es in dieser Prozedur nicht ist... (unsauber aus
         meiner Sicht)
   }
  k                       : INTEGER;
  r,phi,phigrad,phirad,zw : REAL;
  cz                      : Czahl;
 BEGIN
  IF (n > 0) THEN
   BEGIN
    IF (n = 0) THEN
     WriteLn ('Es existiert keine 0-te Wurzel!')
    ELSE
     IF (n = 1) THEN  {Die erste Wurzel aus einer Zahl}
      Caus(c)         {ergibt immer die Zahl selbst   }
     ELSE
      BEGIN
       zw := 1 / n;
       {Ich rechne mit der Polarform}
       Convert2Polar(c,r,phi);
       phi := (180 * phi) / PI; {den absoluten Winkel phi brauche ich in GRAD}
       r := Exp((Ln(r) * zw));  {n-te Wurzel aus dem Radius ziehen           }
       TextColor(19);
       WriteLn ('Ergebnisse der ',n,'-ten Wurzel aus der Zahl ',c.re:4:2,'+(',c.im:4:2,')i');
       WriteLn ('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -');
       TextColor(white);
       {
        In dieser Schleife werden die n Lösungen der n-ten Wurzel berechnet.
        k läuft von 0 bis n-1, wie man es auch beim Rechnen auf dem Blatt verwendet
       }
       FOR k := 0 TO n-1 DO    {k : 0 -> n-1}
        BEGIN
         phigrad := (phi / n) + ((k * 360) / n);
         WHILE (phigrad > 360) DO          {Ich will den Hauptwert des Winkels erhalten,     }
          phigrad := phigrad - 360;        {ziehe also immer 360 Grad ab, falls er größer ist}
         phirad := (PI * phigrad) / 180;
         Convert2karth(r,phirad,cz);
         {Ausgabe der Ergebnisse}
         WriteLn ('k = ',k:2,'       phi = ',phigrad:8:2,'       r = ',r:8:2,'       z = ',cz.re:4:2,'+(',cz.im:4:2,')i');
        END;
       WriteLn;
      END;
   END
  ELSE
   BEGIN
    TextColor(19);
    WriteLn;
    WriteLn ('FEHLEINGABE!');
    WriteLn ('Bitte keine negativen Wurzeln!');
   END;
 END;

{
 Prozedur : Liest die Komplexe Zahl c ein
 Eingabep.: c : Komplexe Zahl
}
PROCEDURE Cein(VAR c : Czahl);
 BEGIN
  Write ('Realteil:     ');
  ReadLn(c.re);
  Write ('Imagin„rteil: ');
  ReadLn(c.im);
  WriteLn;
 END;

{
 Prozedur : Liest 2 komplexe Zahlen ein
 Eingabep.: c1,c2 : Komplexe Zahl
}
PROCEDURE Eingabe2x(VAR c1,c2 : Czahl);
 BEGIN
  WriteLn;
  TextColor(19);
  WriteLn ('erste Zahl');
  TextColor(white);
  Cein(c1);
  TextColor(19);
  WriteLn ('zweite Zahl');
  TextColor(white);
  Cein(c2);
 END;

VAR
 c1,c2,erg     : Czahl;    {Höchstens 2 Zahlen werden gebraucht + Ergebnis}
 ch            : CHAR;     {Die Auswahl des Benutzers                     }
 n             : INTEGER;  {Für Radizieren und Potenzieren                }
 r,phi,phigrad : REAL;     {Für die Polarformen                           }
 progende      : BOOLEAN;  {Programm-abbruch Bedingung                    }
{H A U P T P R O G R A M M}
BEGIN
 progende := FALSE;
 {
  Ich laufe so lange durch, bis der Benutzer mit der Auswahl
  des Hauptprogrammes das Programm abbricht
 }
 WHILE NOT(progende) DO
  BEGIN
   ClrScr;
   TextColor(7);
   {Menue}
   WriteLn ('      Rechner fuer Komplexe Zahlen');
   WriteLn ('- - - - - - - - - - - - - - - - - - - -');
   TextColor(19);
   WriteLn ('(1) Addieren');
   WriteLn ('(2) Subtrahieren');
   WriteLn ('(3) Multiplizieren');
   WriteLn ('(4) Dividieren');
   WriteLn ('(5) Potenzieren');
   WriteLn ('(6) Radizieren');
   WriteLn ('(7) x + iy         -->  r * e^(i*phi)');
   WriteLn ('(8) r * e^(i*phi)  -->  x + iy');
   WriteLn ('(9) Beenden');
   WriteLn;
   TextColor(7);
   WriteLn ('- - - - - - - - - - - - - - - - - - - -');
   WriteLn ('Bitte auswaehlen!');
   TextColor(white);
   ch := ReadKey;
   WriteLn;
   {
    Bei falscher Eingabe stürzt das Programm nicht ab, sondern läuft
    nochmal zum Menue zurück, wo nochmal eine Eingabe gemacht werden kann.
    Gibt der Benutzer aber beim Eingeben der Zahlen einen Buchstaben
    ein, so stürzt das Programm ab (wer das Programm nicht richtig ver-
    wenden will, der soll's halt lassen
   }
   IF (ch = '1') OR (ch = '2') OR (ch = '3') OR
      (ch = '4') OR (ch = '5') OR (ch = '6') OR
      (ch = '7') OR (ch = '8') OR (ch = '9') THEN
    BEGIN
     WriteLn;
     TextColor(7);
     ClrScr;
     {Abfrage der Auswahl und Enstprechende Operation}
     CASE ch OF
      '1' : BEGIN
             WriteLn ('...Addition');
             Eingabe2x(c1,c2);
             Cadd(c1,c2,erg);
            END;
      '2' : BEGIN
             WriteLn ('...Subtraktion');
             Eingabe2x(c1,c2);
             Csub(c1,c2,erg);
            END;
      '3' : BEGIN
             WriteLn ('...Multiplikation');
             Eingabe2x(c1,c2);
             Cmal(c1,c2,erg);
            END;
      '4' : BEGIN
             WriteLn ('...Division');
             Eingabe2x(c1,c2);
             Cdiv(c1,c2,erg);
            END;
      '5' : BEGIN
             WriteLn ('...Potenzieren');
             WriteLn;
             TextColor(19);
             WriteLn ('Zahl eingeben');
             TextColor(white);
             Cein(c1);
             TextColor(19);
             WriteLn ('Potenz eingeben');
             TextColor(white);
             Write ('Ihre Eingabe: ');
             ReadLn (n);
             WriteLn;
             Cpot(n,c1,erg);
            END;
      '6' : BEGIN
             WriteLn ('...Radizieren');
             WriteLn;
             TextColor(19);
             WriteLn ('Zahl eingeben');
             TextColor(white);
             Cein(c1);
             TextColor(19);
             WriteLn ('Wurzel eingeben: ');
             TextColor(white);
             Write ('Ihre Eingabe: ');
             ReadLn (n);
             Crad(n,c1);
            END;
      '7' : BEGIN
             WriteLn ('...In Polarform umwandeln');
             WriteLn;
             TextColor(19);
             Writeln ('Zahl eingeben');
             TextColor(white);
             Cein(c1);
             WriteLn;
             Convert2Polar(c1,r,phi);
             phigrad := (phi * 180) / PI;
             TextColor(7);
             WriteLn ('Komponenten der Zahl');
             WriteLn ('- - - - - - - - - - - - - - - -');
             TextColor(19);
             WriteLn ('Radius : ',r:5:2);
             WriteLn ('Winkel : ',phigrad:5:2);
             TextColor(7);
             WriteLn ('- - - - - - - - - - - - - - - -');
             WriteLn;
             WriteLn ('Zahl in Polarformen:');
             WriteLn ('- - - - - - - - - - - - - - - -');
             TextColor(19);
             WriteLn ('Polarform      : ',r:5:2,'(cos(',phigrad:5:2,') + i sin(',phigrad:5:2,'))');
             WriteLn ('Exponentialform: ',r:5:2,' * e^(i * ',phigrad:5:2,')');
            END;
      '8' : BEGIN
             WriteLn ('...In karthesische Form umwandeln');
             WriteLn;
             TextColor(19);
             WriteLn ('Zahl eingeben');
             TextColor(white);
             Write ('Radius : ');
             ReadLn(r);
             Write ('Winkel : ');
             ReadLn(phi);
             WriteLn;
             Convert2karth(r,phi,c1);
             TextColor(19);
             WriteLn (r:5:2,' * e^(i * ',phigrad:5:2,')');
             TextColor(7);
             Write ('Karthesische Form: ');
             Caus(c1);
            END;
      '9' : progende := TRUE;
     END; {CASE}
     {
      Die ersten 5 Auswahlpunkte haben keine eigene Ausgabe. Dort
      wird das Ergebnis in erg gespeichert und hier ausgegeben. Die
      anderen jedoch haben ihre eingene
     }
     IF (Ord(ch) < 54) THEN
      BEGIN
       TextColor(19);
       Write ('Ergebnis: ');
       TextColor(white);
       Caus(erg);
      END;
    END {von IF (ch = '1') ....}
   ELSE
    BEGIN
     {Hier wird eine Fehleingabe abgefangen}
     WriteLn ('Fehlerhafte Eingabe!');
     WriteLn;
    END;
   {
    Beim Beenden des Programmes wird diese Meldung nicht
    nochmal ausgegeben
   }
   IF (ch <> '9') THEN
    BEGIN
     WriteLn;
     TextColor(7);
     WriteLn ('- - - - - - - - - - - - - - - -');
     WriteLn ('Zum Fortfahren Taste druecken!');
     ReadKey;
    END;
  END; {WHILE}
END. {PROGRAMMENDE}
