______________________________________________________________

Aufgabe 4.1
___________
Quelltext:

MODULE fraction EXPORTS Main;
IMPORT IO;

TYPE 
  FRAC = RECORD zaehler,nenner :INTEGER; (* FRAC: rationale Zahlen als Bruch*)
  END;

VAR ergebnis : FRAC;

(*-------------------------------------------------------------------*)
(* Prozedur ggT, liest Argumente: x, y als Werte,                    *)
(* gibt zurueck: groessten gemeinsamen Teiler von x und y =x         *)
(*-------------------------------------------------------------------*)

PROCEDURE ggT (VALUE x,y : INTEGER) :CARDINAL =

BEGIN

  x:= ABS(x); (* Vorzeichen sind fuer Berechnung unwichtig: eliminieren *)
  y:= ABS(y);

  (* Loesungsalgorithmus nach Euklid *)
  IF x#0 AND y#0 THEN
    WHILE x#y DO
     IF x>y THEN DEC(x,y) ELSE DEC(y,x) END;
    END;
  ELSE
    RETURN 1
  END;

  RETURN x

END ggT;

(*-------------------------------------------------------------------*)
(* Prozedur ReduceFraction, nimmt Argumente: zaehler =x, nenner =y   *)
(* als Variablen, berechnet den gekuerzten Bruch durch Division mit  *)
(* dem groessten gemeinsamen Teiler                                  *)
(*  Aufrufe: ReduceFraction -> ggT                                   *) 
(*-------------------------------------------------------------------*)

PROCEDURE ReduceFraction (VAR x,y : INTEGER) =

VAR teiler : CARDINAL;  (* uebernimmt Wert: ggT *)

BEGIN

  teiler:= ggT(x,y);
  x:= x DIV teiler;
  y:= y DIV teiler;
  IF y<0 THEN x:= -x END; (* ist Nenner negativ, aendert sich das Vorzeichen *)

END ReduceFraction;

(*-------------------------------------------------------------------*)
(* Prozedur GetFraction, nimmt Argumente: x als Variablen,           *)
(* liest einen Bruch ein und weist ihn diesen Variablen zu.          *)
(*  Aufrufe: GetFraction -> ReduceFraction -> ggT                    *)
(*-------------------------------------------------------------------*)

PROCEDURE GetFraction (VAR x : FRAC) =

BEGIN

  x.zaehler:= IO.GetInt();
  IO.Put("/");
  REPEAT
    x.nenner:= IO.GetInt();
  UNTIL x.nenner#0;

  ReduceFraction(x.zaehler,x.nenner);

END GetFraction;

(*-------------------------------------------------------------------*)
(* Prozedur PutFraction, nimmt Argumente: zaehler =x, nenner =y      *)
(* als Werte, keine Rueckgabewerte. Gibt gekuerzten Bruch aus.       *)
(*  Aufrufe: PutFraction -> ReduceFraction -> ggT                    *) 
(*-------------------------------------------------------------------*)

PROCEDURE PutFraction(VALUE x,y : INTEGER) =

BEGIN

  IF y=0 THEN

    IO.Put("Wert unbestimmt\n");

  ELSE

    ReduceFraction(x,y);

    IO.PutInt(x);
    IF ABS(y)>1 THEN
      IO.Put("/");
      IO.PutInt(ABS(y));
    END;

  END;

  IO.Put("\n");

END PutFraction;

(*-------------------------------------------------------------------*)
(* Prozedur Addition, nimmt Argumente: brucha =x, bruchb =y          *)
(* als schreibgeschuetzte Werte, gibt aus: Ergebnis der              *)
(* Addition                                                          *) 
(*  Aufrufe: Addition -> PutFraction -> ReduceFraction -> ggT        *) 
(*-------------------------------------------------------------------*)

PROCEDURE Addition(READONLY x,y : FRAC) : FRAC  =

BEGIN

  ergebnis.zaehler:=x.zaehler*y.nenner+y.zaehler*x.nenner;
  ergebnis.nenner:=x.nenner*y.nenner;

  RETURN ergebnis;

END Addition;

(*-------------------------------------------------------------------*)
(* Prozedur Subtraktion, nimmt Argumente: brucha =x, bruchb =y       *)
(* als schreibgeschuetzte Werte, gibt aus: Ergebnis der              *)
(* Addition                                                          *) 
(*  Aufrufe: Subtraktion -> PutFraction -> ReduceFraction -> ggT     *) 
(*-------------------------------------------------------------------*)

PROCEDURE Subtraktion(READONLY x,y : FRAC) : FRAC =

BEGIN

  ergebnis.zaehler:=x.zaehler*y.nenner-y.zaehler*x.nenner;
  ergebnis.nenner:=x.nenner*y.nenner;

  RETURN ergebnis;

END Subtraktion;

(*-------------------------------------------------------------------*)
(* Prozedur Multiplikation, nimmt Argumente: brucha =x, bruchb =y    *)
(* als schreibgeschuetzte Werte, gibt aus: Ergebnis der              *)
(* Addition                                                          *) 
(*  Aufrufe: Multiplikation -> PutFraction -> ReduceFraction -> ggT  *) 
(*-------------------------------------------------------------------*)

PROCEDURE Multiplikation(READONLY x,y : FRAC) : FRAC =

BEGIN

  ergebnis.zaehler:=x.zaehler*y.zaehler;
  ergebnis.nenner:=x.nenner*y.nenner;

  RETURN ergebnis;

END Multiplikation;

(*-------------------------------------------------------------------*)
(* Prozedur Division, nimmt Argumente: brucha =x, bruchb =y          *)
(* als schreibgeschuetzte Werte, gibt aus: Ergebnis der              *)
(* Division                                                          *) 
(*  Aufrufe: Division -> PutFraction -> ReduceFraction -> ggT        *) 
(*-------------------------------------------------------------------*)

PROCEDURE Division(READONLY x,y : FRAC) : FRAC =

BEGIN

  ergebnis.zaehler:=x.zaehler*y.nenner;
  ergebnis.nenner:=x.nenner*y.zaehler;

  RETURN ergebnis;

END Division;

(*-------------------------------------------------------------------*)
(* Prozedur Kehrwert, nimmt Argumente: brucha =x                     *)
(* als schreibgeschuetzte Werte, gibt aus: Kehrwert des Bruches      *)
(*  Aufrufe: Kehrwert -> PutFraction -> ReduceFraction -> ggT        *) 
(*-------------------------------------------------------------------*)

PROCEDURE Kehrwert(READONLY x : FRAC) : FRAC =

BEGIN

  ergebnis.zaehler:=x.nenner;
  ergebnis.nenner:=x.zaehler;

  RETURN ergebnis;

END Kehrwert;

VAR Wahl : CHAR;       (* Nimmt Menuewahl auf *)
VAR brucha: FRAC;      (* einzulesende Argumente der Berechnung *)
VAR bruchb : FRAC;

(*********************************************************************)
(* Programm 'fraction' fuehrt Addition, Subtraktion, Multiplikation  *)
(* Division und Kehrwert mit rationalen Zahlen in Form von Bruechen  *)
(* aus.                                                              *)
(*  Aufrufe:                                                         *)
(* 'fraction' -> GetFraction -> ReduceFraction -> ggT;               *)
(* 'fraction' -> Addition/Subtraktion/Multiplikation/Division;       *)
(* 'fraction'-> PutFraction -> ReduceFraction -> ggT                 *) 
(*********************************************************************)

BEGIN

  IO.Put("Dieses Programm fuehrt verschiedene Berechnungen mit Bruechen aus.\n");
  IO.Put("Bitte treffen sie ihre Wahl.");

(* Anzeigen des Menues, abhaengig von Nutzerwahl Operationen ausfuehren *)

  LOOP

    IO.Put("\n[1] Addition\n");
    IO.Put("[2] Subtraktion\n");
    IO.Put("[3] Multiplikation\n");
    IO.Put("[4] Division\n");
    IO.Put("[5] Kehrwert\n");
    IO.Put("[Q] Quit\n");

    Wahl:= IO.GetChar();
    EVAL IO.GetLine();

    (**Ereignisbehandlung**)
    (* Fall: Operation gewaehlt = Brueche einlesen/ Operation ausfuehren *)
    (* wiederholen. Fall: Abbruch gewaehlt = Schleife verlassen.         *)

    IF Wahl= '1' THEN
      IO.Put("\nBitte geben sie zwei zu addierende Brueche ein:\n");
      GetFraction(brucha);
      IO.Put("+");
      GetFraction(bruchb);
      IO.Put("\nErgebnis:");
      ergebnis:= Addition(brucha,bruchb);
      PutFraction(ergebnis.zaehler,ergebnis.nenner);
    ELSIF Wahl='2' THEN
      IO.Put("\nBitte geben sie zwei zu subtrahierende Brueche ein:\n");
      GetFraction(brucha);
      IO.Put("-");
      GetFraction(bruchb);
      IO.Put("\nErgebnis:");
      ergebnis:= Subtraktion(brucha,bruchb);
      PutFraction(ergebnis.zaehler,ergebnis.nenner);
    ELSIF Wahl='3' THEN
      IO.Put("\nBitte geben sie zwei zu multiplizierende Brueche ein:\n");
      GetFraction(brucha);
      IO.Put("*");
      GetFraction(bruchb);
      IO.Put("\nErgebnis:");
      ergebnis:= Multiplikation(brucha,bruchb);
      PutFraction(ergebnis.zaehler,ergebnis.nenner);
    ELSIF Wahl='4' THEN
      IO.Put("\nBitte geben sie zwei zu dividierende Brueche ein:\n");
      GetFraction(brucha);
      IO.Put("DIV");
      GetFraction(bruchb);
      IO.Put("\nErgebnis:");
      ergebnis:= Division(brucha,bruchb);
      PutFraction(ergebnis.zaehler,ergebnis.nenner);
    ELSIF Wahl='5' THEN
      IO.Put("\nBitte geben sie den zu bestimmenden Bruch ein:\n");
      GetFraction(brucha);
      IO.Put("\nErgebnis:");
      ergebnis:= Kehrwert(brucha);
      PutFraction(ergebnis.zaehler,ergebnis.nenner);
    ELSIF Wahl='q' OR Wahl='Q' THEN
      EXIT
    END;
    EVAL IO.GetLine();

  END;

END fraction.

Testlauf:

Dieses Programm fuehrt verschiedene Berechnungen mit Bruechen aus.
Bitte treffen sie ihre Wahl.
[1] Addition
[2] Subtraktion
[3] Multiplikation
[4] Division
[5] Kehrwert
[Q] Quit
1

Bitte geben sie zwei zu addierende Brueche ein:
2
/5
+1
/10

Ergebnis:1/2

[1] Addition
[2] Subtraktion
[3] Multiplikation
[4] Division
[5] Kehrwert
[Q] Quit
2

Bitte geben sie zwei zu subtrahierende Brueche ein:
4
/5
-3
/8

Ergebnis:17/40

[1] Addition
[2] Subtraktion
[3] Multiplikation
[4] Division
[5] Kehrwert
[Q] Quit
3

Bitte geben sie zwei zu multiplizierende Brueche ein:
5
/7
*1
/2

Ergebnis:5/14

[1] Addition
[2] Subtraktion
[3] Multiplikation
[4] Division
[5] Kehrwert
[Q] Quit
4

Bitte geben sie zwei zu dividierende Brueche ein:
2
/3
DIV1
/3

Ergebnis:2

[1] Addition
[2] Subtraktion
[3] Multiplikation
[4] Division
[5] Kehrwert
[Q] Quit
5

Bitte geben sie den zu bestimmenden Bruch ein:
1
/5

Ergebnis:5

[1] Addition
[2] Subtraktion
[3] Multiplikation
[4] Division
[5] Kehrwert
[Q] Quit
1

Bitte geben sie zwei zu addierende Brueche ein:
1
/5
+4
/5

Ergebnis:1

[1] Addition
[2] Subtraktion
[3] Multiplikation
[4] Division
[5] Kehrwert
[Q] Quit
3

Bitte geben sie zwei zu multiplizierende Brueche ein:
3
/7
*7
/6

Ergebnis:1/2

[1] Addition
[2] Subtraktion
[3] Multiplikation
[4] Division
[5] Kehrwert
[Q] Quit
q

Testlaufende.