/*
 * Aufgabe 25:
 * -----------
 *
 * Entwerfen und implementieren Sie eine Klasse Bruch zur Darstellung und
 * Verarbeitung von Dezimalbrüchen. Alle numerischen Werte sollen hier vom
 * Typ int sein.
 *
 *	a) Realisieren Sie Konstruktoren nach folgenden Vorgaben:
 *
 *		* Der default-Konstruktor soll einen Bruch ergeben, der
 *		  den Wert 1 repräsentiert.
 *		* Der Aufruf eines Konstruktors mit einem ganzzahligen
 *		  Argument x soll einen Bruch ergeben, der den Wert x
 *		  repräsentiert.
 *		* Der Aufruf eines Konstruktors mit zwei ganzzahligen
 *		  Argumenten x und y soll einen Bruch ergeben, der den
 *		  Wert x/y repräsentiert.
 *
 *	b) Realisieren Sie Methoden zum Zugriff auf die Attribute (welche
 *	   Attribute hat Ihre Klasse?).
 *
 *	c) Realisieren Sie Methoden zur Addition, Subtraktion, Multiplikation
 *	   und Division nach der "Schulmethode".
 *	   Beispiel zur Notation: Die Methode addiere eines Bruchobjektes B2
 *	   soll als Argument eine Referenz auf ein weiteres Bruchobjekt B2
 *	   erwarten und eine Referenz auf ein neues Bruchobjekt B3 zurück-
 *	   liefern. Das Bruchobjekt B3 soll hierbei den Bruch B1 + B2 reprä-
 *	   sentieren.
 *
 *	d) Realisieren Sie eine Methode zum Kürzen eines Bruches. Diese Methode
 *	   soll das aktuelle Objekt ggfs. so modifizieren, dass Zähler und
 *	   Nenner teilerfremd sind.
 *	   Verwenden Sie diese Methode, um sicher zu stellen, dass alle Brüche
 *	   nach jeder arithmetrischen Operation bzw. nach ihrer Konstruktion
 *	   gekürzt sind.
 */
class Bruch
{
	/* Attribute: Zaehler und Nenner des Bruchs */
	private int Zaehler, Nenner;

	/* Hilfsmethode */
	public String s()
	{
		return (Zaehler % Nenner == 0
			? "" + (Zaehler / Nenner)
			: Zaehler + "/" + Nenner);
	}

	/* default-Konstruktor */
	Bruch()
	{
		Zaehler = Nenner = 1;
	}

	/* Konstruktor zum Erstellen eines Bruchs für den Wert x */
	Bruch(int x)
	{
		Zaehler = x; Nenner = 1;
	}

	/* Konstruktor zum Erstellen eines Bruchs für den Wert x/y */
	Bruch(int x, int y)
	{
		Zaehler = x;
		setNenner(y);
	}

	/* Zugriffsmethoden: */
	public int getZaehler()	{ return (Zaehler); }
	public int getNenner()	{ return (Nenner); }
	
	public void setZaehler(int x)
	{
		Zaehler = x;
		kuerzeBruch();
	}

	public void setNenner(int y)
	{
		if ((Nenner = y) == 0) {
			Nenner = 1;
			System.err.println("Bruch " + Zaehler + "/0 nicht " +
				"darstellbar. Anpassung zu " + s() + "!");
		}
		else
			kuerzeBruch();
	}

	/* Methode zum Ermitteln des größten gemeinsamen Teilers */
	private int ggT(int u, int v)
	{
		int t;

		/* Das Euklidsche Verfahren beruht auf der Tatsache, dass,
		 * wenn u größer als v ist, der größte gemeinsame Teiler
		 * von u und v gleich dem größten gemeinsamen Teiler von
		 * v und u - v ist.
		 */
		for (; u > 0; u = u - v)
			if (u < v) {
				/* u und v vertauschen */
				t = u;
				u = v;
				v = t;
			}

		return (v);
	}

	/* Methode zum Kürzen eines Bruches */
	private void kuerzeBruch()
	{
		int n;

		/* Normalisieren des Bruches: neg. Vorzeichen nur im Zaehler */
		if (Nenner < 0) {
			Zaehler = -Zaehler;
			Nenner = -Nenner;
		}

		/* Größten gemeinsamen Teiler ermitteln und Zaehler und
		 * Nenner durch diesen teilen.
		 * WICHTIG: Beträge von Zaehler und Nenner verwenden!
		 */
		Zaehler /= (n = ggT(Math.abs(Zaehler), Math.abs(Nenner)));
		Nenner /= n;
	}

	/* Methode zum Addieren von Brüchen */
	public Bruch add(Bruch b)
	{
		/* vermutlich die schnellste und eleganteste Methode (von
		 * der Implementierung gesehen), da der Bruch Konstruktor
		 * sowieso den Bruch erst kürzt.
		 * Das spart das Berechnen des kgV.
		 */
		return (new Bruch(Zaehler * b.Nenner + b.Zaehler * Nenner,
			Nenner * b.Nenner));
	}

	/* Methode zum Subtrahieren von Brüchen */
	public Bruch sub(Bruch b)
	{
		/* vermutlich die schnellste und eleganteste Methode (von
		 * der Implementierung gesehen), da der Bruch Konstruktor
		 * sowieso den Bruch erst kürzt.
		 * Das spart das Berechnen des kgV.
		 */
		return (new Bruch(Zaehler * b.Nenner - b.Zaehler * Nenner,
			Nenner * b.Nenner));
	}

	/* Methode zum Multiplizieren von Brüchen */
	public Bruch mul(Bruch b)
	{
		return (new Bruch(Zaehler * b.Zaehler, Nenner * b.Nenner));
	}

	/* Methode zum Dividieren von Brüchen */
	public Bruch div(Bruch b)
	{
		/* Zaehler von b darf nicht 0 sein */
		if (b.Zaehler == 0) {
			System.err.println("Division durch 0!");
			return (null);
		}

		return (new Bruch(Zaehler * b.Nenner, Nenner * b.Zaehler));
	}
}

public class Aufgabe25
{
	public static void main(String[] argv)
	{
		Bruch b1 = new Bruch(2678, -824);
		Bruch b2 = new Bruch(12, -21);
		Bruch b3 = b1.div(b2);

		System.out.println(b1.s() + " / " + b2.s() + " = " + b3.s());
	}
}

