Probleme mit dem Überladen von Operatoren (gelöst)



  • Hallo,
    ich muss die Operatoren +-*/ für rationale Zahlen überladen.
    Dabei sollen die einzelnen Rechenarten aufeinander abgebildet werden um Programmierarbeit zu sparen. Beispiele:

    (- 1/2) + (- 1/4 ) = (- 1/2) - (+ 1/4)

    (+ 1/2) * (+ 1/4 ) = (+ 1/2) / (+ 4/1)

    Der Programmrahmen sieht so aus:

    #include <iostream>
    #include "RationaleZahl.h"
    
    using namespace std;
    
    //
    // Operatoren: + - * /
    //
    RationaleZahl &operator +(const RationaleZahl &l, const RationaleZahl &r) {
      cout << '(' << l.Zaehler << '/' << l.Nenner << ')' << "plus"
           << '(' << r.Zaehler << '/' << r.Nenner << ')'
           << "ist noch nicht implementiert" << endl;
    //  return ???;
    }
    RationaleZahl &operator -(const RationaleZahl &l, const RationaleZahl &r) {
      cout << '(' << l.Zaehler << '/' << l.Nenner << ')' << "minus"
           << '(' << r.Zaehler << '/' << r.Nenner << ')'
           << "ist noch nicht implementiert" << endl;
    //  return ???;
    }
    RationaleZahl &operator *(const RationaleZahl &l, const RationaleZahl &r) {
      cout << '(' << l.Zaehler << '/' << l.Nenner << ')' << "mal"
           << '(' << r.Zaehler << '/' << r.Nenner << ')'
           << "ist noch nicht implementiert" << endl;
    //  return ???;
    }
    RationaleZahl &operator /(const RationaleZahl &l, const RationaleZahl &r) {
      cout << '(' << l.Zaehler << '/' << l.Nenner << ')' << "durch"
           << '(' << r.Zaehler << '/' << r.Nenner << ')'
           << "ist noch nicht implementiert" << endl;
    //  return ???;
    }
    
    //
    // Ausgabeoperator: <<
    //
    ostream &operator << (ostream & o, const RationaleZahl &r) {
      o << "ostream &operator << (ostream & o, RationaleZahl r)"
        << " noch nicht implementiert" << endl;
      return o;
    }
    

    Mein genaues Problem ist nun folgendes:

    Ich könnte ja nun für alle Rechenarten einen Algorithmus entwickeln. Vorzeichen unterscheiden und dann die Rechnungen ausführen. Aber das möchte ich ja nicht.
    Wie bekomme ich es nun hin, dass er bei einer / Operation, eine * Operation ausführt?



  • a/(1/b) == a*b



  • Braunstein schrieb:

    a/(1/b) == a*b

    Ja, so schön einfach hatte ich mir das auch schon gedacht. Nur leider weiss ich überhaupt nicht, wie ich das dort anwenden soll. Wenn ich im

    RationaleZahl &operator /(const RationaleZahl &l, const RationaleZahl &r) {
      cout << '(' << l.Zaehler << '/' << l.Nenner << ')' << "durch"
           << '(' << r.Zaehler << '/' << r.Nenner << ')'
           << "ist noch nicht implementiert" << endl;
    //  return ???;
    }
    

    Block die Zuweisung nach dem Muster a/(1/b) == a*b mache, beachtet er diese gar nicht.



  • Multiplikation durch Division zu implementieren ist nicht allzu klug.



  • Das ist schon richtig, aber vielleicht wars ja die Aufgabe.
    @Kinkster
    Du mußt doch für mindestens zwei der Operatoren (/ und +) erstmal was schreiben. Weißt du wie Addition bei rationalen Zahlen funktioniert?
    Schreibs auf und versuch es zu implementieren.



  • Okay, das habe ich nun gemacht.
    Da ich mich aber gestern etwas komisch ausgedrueckt habe, noch eine kleine Erklaerung: Ich habe nun die Operationen + und * programmiert. Die Ergebnisse sind auch korrekt. Wie kann ich nun auf - und / zugreifen? Die Rechenregeln kenn ich (hab ja im ersten Post ein Beispiel gegeben).

    #include <iostream>
    #include "RationaleZahl.h"
    
    using namespace std;
    
    int ggt ( unsigned int a , unsigned int b ) { // diese Funktion ermittelt den ggt
      if(b!=0){
       return ggt(b, a%b);
      }
      else{
        return a;
      }
    }
    
    //
    // Operatoren: + - * /
    //
    RationaleZahl &operator +(const RationaleZahl &l, const RationaleZahl &r) {
      static RationaleZahl q;
      unsigned int n1,n2,N1,N2,Z1,Z2,Z1r,N1r,Zr,Nr;	  
      Z1=l.Zaehler;
      N1=l.Nenner;
      Z2=r.Zaehler;
      N2=r.Nenner;
    
      n1=N1/ggt(N1,N2);
      n2=N2/ggt(N1,N2);
    
      N1r=n1*n2*ggt(N1,N2);//gekuerzter  und berechneter Nenner
    
      if ((l.Zaehler==0 && l.Nenner==0) ||(r.Zaehler==0 && r.Nenner==0)){     	//Ausnahmen
        KeineZahl Ausnahme;
        throw Ausnahme;
      } 
    
      if (l.Nenner==0 || r.Nenner==0){
        MinusUnendlichUndPlusUnendlich Ausnahme;
        throw Ausnahme;
      }
    
      if((l.Vorzeichen !='+'&& l.Vorzeichen !='-') || (r.Vorzeichen != '+'&&r.Vorzeichen !='-')){
        FalschesVorzeichen Ausnahme;
        throw Ausnahme;	
      }
    
      if ( l.Vorzeichen == '-' && r.Vorzeichen == '-' ) {				// 1.Fall: Beide Vorzeichen sind minus
        Z1r=Z1*n2+Z2*n1;    //gekuerzter  und berechneter Zaehler
        Zr=Z1r/ggt(Z1r,N1r);
        Nr=N1r/ggt(Z1r,N1r);
    
        q.Vorzeichen ='-';
        q.Zaehler=Zr;
        q.Nenner=Nr;
      }	 
      if ( l.Vorzeichen == '+' && r.Vorzeichen=='+' ) {				// 2.Fall: Beide Vorzeichen sind plus					 
        Z1r=Z1*n2+Z2*n1;  //gekuerzter  und berechneter Zaehler  
        Zr=Z1r/ggt(Z1r,N1r);
        Nr=N1r/ggt(Z1r,N1r);
    
        q.Vorzeichen ='+';
        q.Zaehler=Zr;
        q.Nenner=Nr; 
      }	
    
      if ( l.Vorzeichen=='-' && r.Vorzeichen=='+' ){ 				//3.Fall: Links Minus, Rechts Plus	
        if ((Z1*n2)>(Z2*n1)){
          Z1r=Z1*n2-Z2*n1;    //gekuerzter  und berechneter Zaehler	
          Zr=Z1r/ggt(Z1r,N1r);
          Nr=N1r/ggt(Z1r,N1r);
    
          q.Vorzeichen='-';
          q.Zaehler=Zr;
          q.Nenner=Nr;
        }
      else if((Z1*n2)==(Z2*n1)){
          q.Vorzeichen='+';
          q.Zaehler='0';
          q.Nenner='0';
        }
        else{
          Z1r=Z2*n1-Z1*n2;    //gekuerzter  und berechneter Zaehler	
          Zr=Z1r/ggt(Z1r,N1r);
          Nr=N1r/ggt(Z1r,N1r);
    
          q.Vorzeichen='+';
          q.Zaehler=Zr;
          q.Nenner=Nr;
        }
    }
      if ( l.Vorzeichen=='+' && r.Vorzeichen=='-' ) { 				//4.Fall: Links Plus , Rechts Minus
        if ((Z1*n2) > (Z2*n1)){
          Z1r=Z1*n2-Z2*n1;    
          Zr=Z1r/ggt(Z1r,N1r);
          Nr=N1r/ggt(Z1r,N1r);
          q.Vorzeichen='+';
          q.Zaehler=Zr;
          q.Nenner=Nr;
        }
        else if((Z1*n2)==(Z2*n1)){
          q.Vorzeichen='+';
          q.Zaehler='0';
          q.Nenner='0';
        }
        else{
          Z1r=Z2*n1-Z1*n2;    
          Zr=Z1r/ggt(Z1r,N1r);
          Nr=N1r/ggt(Z1r,N1r);
          q.Vorzeichen='-';
          q.Zaehler=Zr;
          q.Nenner=Nr;
        }
      }
    
    return q;
    }
    
    //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------		  
    //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------		  
    
    RationaleZahl &operator -(const RationaleZahl &l, const RationaleZahl &r) {
      static RationaleZahl q;
    
      return q;
    }
    
    //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------		  
    //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------	
    
    RationaleZahl &operator *(const RationaleZahl &l, const RationaleZahl &r) {
      static RationaleZahl q;
    
    	unsigned int N1,N2,Z1,Z2,z11,z22,n11,n22,Zr,Nr,a;
    	Z1=l.Zaehler;
    	N1=l.Nenner;
    	Z2=r.Zaehler;
    	N2=r.Nenner;
    
    	if ((l.Zaehler==0 && l.Nenner==0) || (r.Zaehler==0 && r.Nenner==0)){
    		KeineZahl Ausnahme;
    		throw Ausnahme;
    	} 
    	if ((l.Zaehler ==0) && (r.Nenner ==0) || ((l.Nenner ==0) && (r.Zaehler ==0))){
    		NullMalUnendlich Ausnahme;
    		throw Ausnahme;
    	}	
    
    	if((l.Vorzeichen !='+'&& l.Vorzeichen !='-') || (r.Vorzeichen != '+'&& r.Vorzeichen !='-')){
    		FalschesVorzeichen Ausnahme;
    		throw Ausnahme;	
    	}
    
    	z11=Z1/ggt(Z1,N2);
    	z22=Z2/ggt(Z2,N1);
    	n11=N1/ggt(Z2,N1);
    	n22=N2/ggt(Z1,N2);
    	Zr=z11*z22;
    	Nr=n11*n22;
    	a=ggt(Zr,Nr);
    	q.Zaehler=Zr/a;
    	q.Nenner=Nr/a;
    	if ((l.Vorzeichen=='-')&&(r.Vorzeichen=='-')){	
    		q.Vorzeichen='+';		 
    	}
    	if ((l.Vorzeichen=='+')&&(r.Vorzeichen=='+')){	
    		q.Vorzeichen='+';		 
    	}
    	if ((l.Vorzeichen=='+')&&(r.Vorzeichen=='-')){	
    		q.Vorzeichen='-';		 
    	}
    	if ((l.Vorzeichen=='-')&&(r.Vorzeichen=='+')){	
    		q.Vorzeichen='-';		 
    	}
    
      return q;
    }
    
    //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------		  
    //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    RationaleZahl &operator /(const RationaleZahl &l, const RationaleZahl &r) {
    
    static RationaleZahl q;
    
      return q;
    }
    
    //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------		  
    //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    //
    // Ausgabeoperator: <<
    //
     ostream &operator << (ostream & o, const RationaleZahl &r) {
      o<<"(";
      if (r.Zaehler==0&&r.Nenner>0){
        o<<0;
      }
      else if(r.Zaehler>0 && r.Nenner==0){
        o<<r.Vorzeichen<<"Unendlich"<< endl;
      }	
      else if(r.Nenner==0 && r.Zaehler==0){
        o<<"NaN";
      }
      else {
        o<<r.Vorzeichen << r.Zaehler<<'/'<< r.Nenner;	
      }
      o <<')';
      flush;
      return o;
    }
    


  • Für - mußt du lediglich das Vorzeichen des Subtrahenden umdrehen:

    RationaleZahl operator -(const RationaleZahl &l, const RationaleZahl &r) {
      RationaleZahl r2=r;
      if(r2.Vorzeichen='-')
        r2.Vorzeichen='+';
      else
        r2.Vorzeichen='-';
    
      return l+r2;
    }
    

    Für / vertauschst du Zähler und Nenner des Dividenden:

    RationaleZahl operator /(const RationaleZahl &l, const RationaleZahl &r) {
      RationaleZahl r2=r;
      std::swap(r2.Zaehler,r2.Nenner);
    
      return l*r2;
    }
    

    PS: Und du solltest statt einer Referenz auf einen statischen Wert lieber einen Wert zurückgeben - sonst bekommst du Probleme, wenn du mehrere Operatoren in einem Ausdruck verwendest.



  • Hallo,

    / kannst du mit * definieren, indem du Zähler und Nenner von r vertauschst. Du hast ja sicher einen Konstruktor mit zwei Werten. Dann müsste das so gehen.

    // /operator
    RationaleZahl temp(r.Nenner, r.Zaehler);
    return l*temp;
    

    operator - dann mit *-1

    RationaleZahl temp(r*RationaleZahl(-1,1));
    return l+temp;
    

    Zu deinem +operator.
    Die Testst auf 0 im Nenner würde ich in den Konstruktor verlegen. Wenn so eine Zahl garnicht erst erzeugt werden kann, brauchst du später nicht zu testen und du sparst dir Exceptions im operator.
    Versuche die ggt-Aufrufe zu minimieren indem du das Ergebnis einer temporären Variable zuweist und damit rechnest. ggt kann nämlich recht aufwendig sein.

    [edit]War wohl etwas spät 🙂 [edit]



  • Hallo,

    vielen Dank. Habe es mit Euren Tipps hinbekommen!


Log in to reply