Unbekannter fehler Matrizen Multiplizieren



  • ok danke hab das mit den mebmer functions nochmal nachgeschlagen allerdings wird meine Matrix nur mit nullen gefüllt. Weis jemand warum?

    #include <iostream>
    #include <vector>
    
    class matrix{
    
    private:
    
         unsigned int row, col;
         std::vector<unsigned int> data;
    
    public:
    
         matrix(unsigned int row,unsigned int col) : row(row),col(col),data(row*col){}
    
         void fill_matrix(){
    
             for(unsigned int i=0;i<row*col;i++){
                data.push_back(i);
             }
         }
    
         void print_matrix(){
    
         unsigned int a=0;
    
         for(unsigned int i=0;i<col;i++){
    
             for (unsigned int j=0;j<row;j++){
                 std::cout<<data[a];
    
                 }
    
                 std::cout<<"\n";
                 a++;
             }
         }
    };
    
    int main()
    {
    
         matrix a(3,3);
         a.fill_matrix();
         a.print_matrix();
    
    }
    


  • eindeutig. beim fill fügst du einfach neue elemente hinten ran statt die bestehenden elemente zu ändern.



  • Welchen Wert hat denn a (Zeile 31)?

    std::cout<<data[a];
    

    gib ihn doch einfach mal mit aus.



  • Danke leute das waren die beiden fehler 🙂 hatte auch genau an die beiden dinge gedacht und ein bisschen rumprobiert.

    Kann ich eigentlich was da in fill steht in den kontruktor packen?

    Edit: habs einfach gemacht und hat geklappt 🙂



  • jo ist np, indem du im konstruktor "this->fill_matrix();" schreibst oder - wenn du die methode ansonsten gar nicht möchtest - einfach den code aus "fill_matrix" in den konstruktor hineinkopierst.



  • ok danke jetzt hab ich das nächste Problem wie schreibe ich memberfunktionen um sowas hier benutzen kann?

    Matrix a;
    Matrix b;
    
    Matrix c = a*b;
    

    Also der logische ihnhalt der Funktion ist mir klar als non member function bekomm ich das auch hin in dem ich einfach die 2 Matrizen als Argument übergebe aber wie man was als member schreibt ist mir schleierhaft.

    Hat jemand einen tip ?



  • das macht man in der regel so:

    class matrix
    {
        // ...
    public:
        // ...
        matrix& operator*= (matrix const& rhs)
        {
            // code zum multiplizieren von (*this) mit rhs
            return *this;
        }
    };
    const matrix operator* (matrix lhs, matrix const& rhs) // kopie im parameter machen -> codeoptimierung manchmal besser!
    {
        return lhs *= rhs;
    }
    

    matrizen zu multiplizieren ist ein wenig spezieller als z.b. vektoren zu addieren, da sich die tatsächliche grösse von (*this) in operator*= ändern kann. zur gewährleistung der strong guarantee, solltest du eine kopie machen (bei der instanzierung schon die grösse bestimmen!), da reinrechnen und dann (*this) mit der kopie swappen. das swappen auch in eine methode auslagern und dann bequem die datenzeiger swappen für mehr speed. und da deine matrix keine template-klasse ist, ab besten auch std::swap spezialisieren und deine eigene swap-methode aufrufen.



  • ok danke aber das ist noch zu hoch für mich. da muss ich erstmal im Lehrbuch weiter kommen. ich dachte vllt schreibt man in der klasse einfach einen Operator und dazu was passiert wenn man 2 Objekte der klasse mit diesem Operator verbindet.

    Naja ich versuch mich mal reinzuarbeiten danke 👍



  • Es ist mir nicht klar, ob du matrix-produkt oder das elementweise-Produkt haben willst (beides wird je nach Sprache mit * notiert). adfasdfs gezeigter Code passt gut zum elementweisen produkt und wird so mit Sicherheit auch beim matrix-produkt funktionieren. Allerdings ist es beim echten Matrixprodukt besser wegen der Probleme mit der Matrixgröße sowie aliasing op = mithilfe von op zu implementieren, und nicht wie üblich umgekehrt. Das spart eine Kopie (du brauchst bei dem hier gezeigten Ansatz immer 2 temporäre Kopien bei Benutzung von op*)

    @Photon

    das wird heir ja gemacht. Nur nicht dein Code für a*b sondern a*=b und dann wird a*b mithilfe dieses operators implmentiert mittels:

    c=ab
    =>
    c=a;
    c
    =b;


  • Mod

    Photon schrieb:

    ok danke aber das ist noch zu hoch für mich. da muss ich erstmal im Lehrbuch weiter kommen. ich dachte vllt schreibt man in der klasse einfach einen Operator und dazu was passiert wenn man 2 Objekte der klasse mit diesem Operator verbindet.

    Das geht auch. Wo wäre da denn der große Unterschied gegenüber dem, was adfasdf gezeigt hat, dass du das nicht mehr verstehst? Das ist doch das gleiche, wie als Member, bloß eben als freie Funktion.

    Der Unterschied zwischen der Implementierung als Memberfunktion und als freie Funktion ist, dass bei der freien Funktion implizite Konvertierungen für den linksseitigen Parameter möglich sind (was man oft möchte!). Für ein paar Feinheiten der Operatorüberladung, die so detailliert wohl nicht in jedem Lehrbuch stehen dürften, siehe den mehrteiligen Magazinartikel, der hier beginnt:
    http://www.c-plusplus.net/forum/232010



  • otze schrieb:

    adfasdfs gezeigter Code passt gut zum elementweisen produkt und wird so mit Sicherheit auch beim matrix-produkt funktionieren. Allerdings ist es beim echten Matrixprodukt besser wegen der Probleme mit der Matrixgröße sowie aliasing op = mithilfe von op zu implementieren, und nicht wie üblich umgekehrt. Das spart eine Kopie (du brauchst bei dem hier gezeigten Ansatz immer 2 temporäre Kopien bei Benutzung von op*)

    oh, das habe ich auf die schnelle gar nicht bedacht und ist natürlich besser. 👍



  • moin leute ich probiere gerade mit dem Operatoren überladen rum.

    Habe da ein zwei Unklarheiten.

    matrix operator*(const matrix& rhs){
        matrix ergebnis(rhs.row,rhs.col);
    
        //magic code
    
        return ergebnis;
        }
    

    Wie kann ich in dem falle den lhs ansprechen?

    matrix operator*(const matrix& lhs,const matrix& rhs){
        matrix ergebnis(lhs.row,lhs.col);
    
        //magic code
    
        return ergebnis;
        }
    

    So bekomm ich Fehlermeldungen sollte aber so gehen oder? muss ich da eventuell mit this arbeiten?

    Grüße Photon 😉


  • Mod

    Ja, wenn du das als Memberfunktion implementiert, dann ist die linke Seite das this. Du brauchst natürlich kein explizites this-> überall vor zu schreiben, es ist eine ganz normale Memberfunktion, bloß der Name ist etwas exotisch:

    class Foo
    {
      int i;
      int get_i() { return i; };
      // Ganz analog, bloß anderer Funktionsname:
      int operator()() { return i; }
    };
    
    // ...
    
    Foo f;
    cout << f.get_i() << f(); // Geben beide den Wert von i
    

    Wenn du es natürlich als freie Funktion implementierst, dann hast du beide Objekte explizit als Parameter der Operatorfunktion. Aber das wichtige ist: Operatorüberladung ist nichts anderes als normale Funktionen, bloß der Name ist ein bisschen anders.



  • Danke Seppj habs kapiert 👍 meine funtkion sieht jetzt so aus

    matrix operator*(const matrix& rhs){
    
        matrix ergebnis(row,col);
        unsigned int a=0;
    
        for(unsigned int i=0;i<col;i++){
            for(unsigned int j=0;j<row;j++){
                ergebnis.data[a]=data[i*col+j]*rhs.data[j*col+i];
                a++;}
        }
        return ergebnis;
        }
    

    Hat jemand n tip wie ich das so optimieren kann das es nicht nur für gleich große Matrizen funtioniert? 😕

    dann habe ich eben sowas versucht um eine Matrix einfach ber cout darzustellen aber es ging nicht. Gibt's da was besonderes zu beachten?

    void operator<<(){
    
        //magic
    
        }
    

  • Mod

    Photon schrieb:

    Hat jemand n tip wie ich das so optimieren kann das es nicht nur für gleich große Matrizen funtioniert? 😕

    Du musst erstmal mathematisch die Frage klären, was geht und was nicht. Was muss für M, N, O, und P gelten, wenn man eine MxN-Matrix mit einer OxP-Matrix multiplizieren will? Wenn du das beantworten kannst, ergibt sich eigentlich ganz von alleine der nötige Code.

    dann habe ich eben sowas versucht um eine Matrix einfach ber cout darzustellen aber es ging nicht. Gibt's da was besonderes zu beachten?

    void operator<<(){
        
        //magic
        
        }
    

    Ja. Dieser Operator will linksseitig ja ein Objekt vom Typ ostream haben (von dieser Klasse ist cout). Da du der ostream-Klasse nicht einfach irgendwelche Memberfunktionen hinzu fügen kannst, muss es eine freie Funktion sein. Außerdem kann man ostreams nicht kopieren, also müssen diese zwangsläufig als Referenz übergeben werden. Und zu guter Letzt willst du den ostream selbst noch als Rückgabewert zurück geben, damit man mehrere Aufrufe aneinanderreihen kann, a la cout << a << b << c; . Das ist in Wirklichkeit (((cout << a) << b) << c) , jeder Aufruf gibt aber cout selber zurück, daher kann man auf das Ergebnis wieder ein << anwenden. Der Rückgabewert ist auch immens wichtig, wenn du mal einen Eingabeoperator (>>) überladen willst, da darüber die ganze Fehlerprüfung läuft.

    Daher Signatur:

    class foo
    {
      int i;
    };
    
    std::ostream& operator<<(std::ostream &out, const foo& f)
    {
      out << f.i;
      return out;
    }
    

    Doch ein Problem gibt es: i ist ja privat und der Operator aber keine Memberfunktion von foo. Daher gibt es zwei übliche Lösungen:
    1. foo bietet auch noch ein paar public-Funkionen an, die eine Ausgabe erzeugen und die dann vom Operator benutzt werden.
    2. Man macht es als friend.

    Die friend-Syntax wird schnell unübersichtlich, falls foo ein komplizierter Templateausdruck ist. Man denke da dran, dass man friend-Funktionen auch innerhalb der Klasse definieren kann. Sie verhalten sich dann trotzdem wie freie Funktionen (bis auf ein paar Kleinigkeiten bezüglich der Feinheiten der Namensauflösung, für die mir spontan nicht einmal ein Beispiel einfällt, wann es eine Rolle spielen könnte):

    class foo
    {
      int i;
    
      // So passt alles
      friend std::ostream& operator<<(std::ostream &out, const foo& f)
      {
        out << f.i;
        return out;
      }
    };
    

    P.S.: Siehe:
    http://www.c-plusplus.net/forum/232010
    und Google spuckt auch sehr viel zum Thema aus.



  • Das elementweise Matrixprodukt funktioniert nur bei gleich großen Matrizen. Du fragst ja auch nicht, wie du 2 Matrizen mit verschiedener größe addieren kannst. Es macht einfach keinen Sinn.

    nur das "echte" Matrixprodukt kann mit Matrizen unterschiedlicehr Größe klarkommen (aber auch da gibt es Einschränkungen).



  • ok danke

    wie ist das eigentlich bei soner Operator überladen function mit dem lhs kann man den auch als const übergeben?


  • Mod

    Photon schrieb:

    wie ist das eigentlich bei soner Operator überladen function mit dem lhs kann man den auch als const übergeben?

    Es sind die gleichen Regeln wie bei allen Funktionen, nur der Funktionsname ist anders und es ermöglicht eine andere Aufrufsyntax. Du kannst sogar die bekannte Funktionsaufrufsyntax verwenden:

    Foo operator*(const Foo &lhs, const Foo &rhs);
    
    Foo a,b;
    Foo c = operator*(a,b); // Das gleiche wie c = a * b;
    

    Damit sollte sich die Frage nach dem const wohl selbst beantworten: Nutz es, als ob es ganz normale Funktionen mit ganz normalen Parametern wären, mach das const, was du auch dort const machen würdest. Für Implementierungen als Memberfunktion gilt natürlich das gleiche*.

    *: Dir ist schon klar, dass man Memberfunktionen const machen kann, oder? Falls dir die Frage zu dumm vorkommt: Entschuldigung, ich wollte bloß sicher gehen, dass es nicht an den Grundlagen zum const fehlt.



  • Moin,

    Ja SeppJ das das so geht wusste ich ich will aber dann in der main trotzdem diese Schreibweise haben

    Matrix a, b;
    Matrix c=a*b;
    

    Also will ich die memberfunktion so schreiben:

    Matrix Operator*(const Matrix& rhs){...
    

    In dem fall übergebe ich den lhs ja nicht direkt aber ich hätte ihn gerne trotzdem const ich hoffe ihr versteht was ich meine.

    Beste Grüße aus dem kalten Berlin
    Photon



  • SeppJ schrieb:

    Dir ist schon klar, dass man Memberfunktionen const machen kann, oder?


Anmelden zum Antworten