Zahlenproblem bei Bruchrechnung

Moch

Bekanntes Mitglied
Hallo,
Ich habe da ein kleines Problem.

Zur Lage:
Ich implementiere gerade die Bruchrechnung, die ich für einen Optimierungsalgorithmus benötige.
Probleme habe ich mit dem Kürzen von Brüchen bei der Addition. Siehe Quelltextausschnitte unten:

Die Addition gibt soweit korrekte Brüche aus, solange ein Bruch nicht mit einem double-Wert erzeugt wird, der neun oder mehr Nachkommastellen hat. An diesem Falle wird ein Bruch 0/0 erzeugt. Diesen Fehler kann ich mir nicht erklären und bitte daher um Eure fachkundliche Hilfe.
Hinweis: Ich weiß, ich kann den Doublewert natürlich kürzen. Dennoch interessiert mich, warum dieses Problem auftritt.

Kann Java entsprechend lange doubles nicht mehr verarbeiten oder liegt da möglicherweise ein ärgerlicher Fehler in meiner Implementierung vor?

Liebe Grüße

Getätige Eingaben (teilweise inkorrekter Code. Nur zur Verdeutlichung. Ein Aufruf von Bruch.add war in der externen Testklasse nicht möglich)

Code:
Bruch param1 = new Bruch(2,4);
Bruch param2 = new Bruch(1,3);
Bruch param3 = new Bruch(1.333);
Bruch param4 = new Bruch(1.333333333);

Bruch.add(param1, param2); //korrektes Ergebnis wird korrekt gekürzt ausgegeben;
Bruch.add(param1, param3); //korrektes Ergebnis wird korrekt gekürzt ausgegeben
Bruch.add(param1, param4); //ausgegebenes Ergebnis: 0/0


Zunächst einmal die Konstruktoren (ja, ich weiß, ich habe mich nicht an unbedingt an die Namenskonventionen gehalten). JavaDoc zur Übersichtlichkeit weggelassen und durch kleine Kommentare ersetzt

Code:
        //Hauptkonstruktor. Damit Änderung nicht mehrfach benötigt
	public Bruch(int zaehler, int nenner){
		if(nenner == 0){
			throw new IllegalArgumentException();
		}
		this.zaehler = zaehler;
		this.nenner = nenner;
		kuerzen();
	}

//****************************************************************

	public Bruch(int zahl){
		this(zahl, 1);
	}

//****************************************************************

	public Bruch(double zahl){
		this(createNumer(zahl), createDenom(zahl));
	}

Als nächstes die beiden Hilfsmethoden des letzten Konstruktors.

Code:
	private static int createNumer(double zahl){
		String sTemp = Double.toString(zahl);
		String sTempB = "";
		String sTempA = "";
		boolean bTemp = false;
		for(int i=0;i<sTemp.length();i++){
			if(sTemp.substring(i, i+1).equals(("."))){
				bTemp = true;
				continue;
			}
			if(bTemp){
				sTempA = sTempA.concat(sTemp.substring(i, i+1));
			}else{
				sTempB = sTempB.concat(sTemp.substring(i, i+1));
			}
		}
		sTemp = sTempB + sTempA;
		return Integer.parseInt(sTemp);
	}

//*********************************************************

	private static int createDenom(double zahl){
		int iTemp = 0;
		String sTemp = Double.toString(zahl);
		boolean bTemp = false;
		for(int i=0; i<sTemp.length();i++){
			if(sTemp.substring(i, i+1).equals(".")){
				bTemp = true;
				continue;
			}
			if(bTemp){
				iTemp++;
			}
		}
		return (int) Math.pow(10, iTemp);
	}

So, nun noch die ebenfalls genutzten Methoden kuerzen(), erweitern() und die obere Additionsfunktion (es gibt weitere, überladene Methoden. Diese wurden jedoch hier nicht verwendet)

Code:
	public void kuerzen(){
		if(this.zaehler!=0){
			int ggt = ggt(this.zaehler, this.nenner);
			this.zaehler = this.zaehler / ggt;
			this.nenner = this.nenner / ggt;
		}else{
			System.out.println("WARNING (1): [bruch.kuerzen()]: numerator == 0");
			System.out.println("WARNING (2): [bruch.kuerzen()]: fraction will not be reduced");
		}
	}

//***************************************************************

	public void erweitern(int num){
		if(num == 0){
			throw new IllegalArgumentException();
		}
		this.zaehler = this.zaehler*num;
		this.nenner = this.nenner*num;
	}

//***************************************************************

	public Bruch add(Bruch a, Bruch b){
		Bruch c = new Bruch(a.zaehler,a.nenner);
		Bruch d = new Bruch(b.zaehler,b.nenner);
		c.erweitern(b.nenner);
		d.erweitern(a.nenner);
		return(new Bruch(c.zaehler+d.zaehler,c.nenner));
	}
 
Zuletzt bearbeitet:
S

Spacerat

Gast
Hmm... du entwickelst hier eine Klasse "Bruch" und fällst bei Dezimalbüchen glatt darauf rein, dass es auch endlos periodische Brüche gibt? :eek:
Double kann deswegen nämlich einige Zahlen gar nicht darstellen, könnte sein, dass dein Problem etwas damit zu tun hat. Ansonsten ist Double, abhängig von der Höhe der Zahl, bis auf 16 Nachkommastellen genau.
Kannst ja mal testen, ob [c]System.out.prlintln((double) wert);[/c] immer das Erwartete ausgibt.
Ich würde da erher eine Methode implementieren, welche gleichzeitig Zähler und Nenner berechnet und in einem Array zurück gibt.
Periodische Dezimalzahlen in Bruchdarstellung
Dieses errechnet z.B. Brüche aus gemischt periodischen Zahlen, sollte sich für gemein hin alle doubles relativ leicht abändern und implementieren lassen.
 

Moch

Bekanntes Mitglied
Sowas blödes.... na ja, der Mathematiker war ich nie. Um ehrlich zu sein, sind die mathematischen Fächer in meinem Studium bisher die schlechtesten Noten gewesen *lacht*

Danke für Deinen Tipp. Ich werde mich morgen mal an Deinen Link rannsetzen. Am liebsten schon heute, aber nachdem wir gerade Essen waren und ich dort zwei Biere genossen habe, werde ich mit sicherheitshalber nicht mehr an irgendwelche Quelltexte / Algorithmen. *lacht*

Also nochmals vielen Danke für den Tipp :)

Würde mich natürlich auch freuen, wenn sonst noch jemand eine Idee hat, was zu besagtem Fehler geführt haben könnte. Mein Algorithmus sollte ansich auch bei der Zahl funktionieren - natürlich hat er die Schwäche, die Spacerat beschrieben hat, aber dennoch würde mich interessieren, warum hier meine Variante nicht funktioniert.

Liebe Grüße
 

Neue Themen


Oben