einfache Matrizenklasse, Vererbung



  • @zeropage sagte in einfache Matrizenklasse, Vererbung:

    Wegen dem Prinzip müsste ich jetzt mehr umschauen. resizeMatrix() ist jetzt protected

    Ganz andere Frage am Rande: Hast du eigentlich einen konkreten Anwendungsfall für resizeMatrix()? So aus dem Bauch heraus würde ich erstmal vermuten, dass sich die Fälle, wo eine Matrix ein neue Größe bekommt, sauberer durch Kopieren in eine neue Matrix umsetzen lassen.

    Beispielsweise wird man bei der Multiplikation nicht-quadratischer Matrizen (wo die resultierende Matrix ja eine andere Größe hat) das Ergebnis ohnehin in eine neue Matrix schreiben. Diese kann man dann gleich mit der richtigen Größe anlegen.

    resize rauszuwerfen und vielleicht sogar rows_ und columns_ konstant zu machen würde das Problem nämlich auch lösen. Nur meine persönliche Meinung (als jemand, der sich am produktivsten fühlt, wenn er am Ende eines Arbeitstags eine negative Anzahl Codezeilen produziert hat 😉 )

    Weitere Anmerkungen:

    std::vector<std::vector<float>> ist nicht sonderlich effizient, da die Matrixelemente dadurch nicht zusammenhängend im Speicher liegen. Besser das in einen std::vector<float>{ rows_ * columns_ }zu packen und die Indizes selbst zu berechnen (z.B. i * columns_ + j bei Row-major-Anordnung).

    Zweistellige Operatoren wie Mat operator*(const float f) implementiert man besser als freie Funktionen. Das hat u.a. den Vorteil, dass der Mat-Typ nicht immer nur auf der linken Seite der Operation vorkommen darf:

    Mat operator*(const Mat& m, const float f);
    Mat operator*(const float f, const Mat& m);
    

    Diese freien Operatoren würden sowohl m * f wie auch f * m erlauben. Letzteres ist nicht möglich, wenn man das nur als Member-Funktion macht.



  • Danke, sind zwar erst ein paar Minuten vergangen, aber ich kann trotzdem schon antworten. resizeMatrix() hat tatsächlich keinen Anwendungszweck. Das kam in einer früheren Version vor, hatte sich dann aber erledigt und mitgeschleppt.

    std::vector<float>{ rows_ * columns_ } hatte ich zuerst auch, bin aber im Zuge der Array-Klasse umgeschwenkt. Werde ich wieder ändern.

    Von den freien Funktionen hatte ich schon gelesen, konnte damit aber nicht umgehen. Mit den freien Operatoren wird mir das aber klar. Danke nochmals.



  • @zeropage sagte in einfache Matrizenklasse, Vererbung:

    Danke, sind zwar erst ein paar Minuten vergangen, aber ich kann trotzdem schon antworten. resizeMatrix() hat tatsächlich keinen Anwendungszweck. Das kam in einer früheren Version vor, hatte sich dann aber erledigt und mitgeschleppt.

    Darauf noch ein Gute-Nacht-Zitat zu später Stunde:
    "Vollkommenheit entsteht offensichtlich nicht dann, wenn man nichts mehr hinzuzufügen hat, sondern wenn man nichts mehr wegnehmen kann." - Antoine de Saint-Exupéry


  • Gesperrt

    @Finnegan sagte in einfache Matrizenklasse, Vererbung:

    Weitere Anmerkungen:
    std::vector<std::vector<float>> ist nicht sonderlich effizient, da die Matrixelemente dadurch nicht zusammenhängend im Speicher liegen. Besser das in einen std::vector<float>{ rows_ * columns_ }zu packen und die Indizes selbst zu berechnen (z.B. i * columns_ + j bei Row-major-Anordnung).

    Ist mir auch aufgefallen: using floatArray = std::vector<std::vector<float>>;

    Ein Vorteil wäre, dass unterschiedliche Spaltenanzahlen je Reihe möglich wären. Aber von solchen Matrizen habe ich noch nie gehört.



  • Am schlimmsten finde ich da allerdings den Namen, denn unter einem floatArray verstehe ich ein Array von Floats, nicht einen std::vector eines std::vectors.



  • @wob Zu seiner Verteidigung: Ein vector ist auch nur ein aufgebohrtes Array. Immerhin muss der Inhalt genauso in einem zusammenhängenden Speicherbereich liegen, wie ein array einer ist.


  • Gesperrt

    @wob Wie findets du dynArray (Abkürzung für (Runtime-) Dynamic Array).



  • @Tyrdal sagte in einfache Matrizenklasse, Vererbung:

    mmerhin muss der Inhalt genauso in einem zusammenhängenden Speicherbereich liegen, wie ein array einer ist.

    std::vector<std::vector<float>> ist da aber ganz anders als float x[10][10], d.h die Speicherbereich hängen eben nicht zusammen.



  • @Tyrdal sagte in einfache Matrizenklasse, Vererbung:

    Zu seiner Verteidigung: Ein vector ist auch nur ein aufgebohrtes Array.

    Darum ging es doch nicht. Zu using floatArray = std::vector<float> hätte ich nichts gesagt. Nur es ist hier eben ein Array eines Arrays (bzw vector eines vectors).

    @titan99_

    Wie findets du dynArray (Abkürzung für (Runtime-) Dynamic Array).

    Tja, der Name passt. Aber warum braucht man das? Das ist auch gar nicht mein Punkt gewesen.



  • @wob Ah ok, gut vector von vector benutz ich eh nie, weil es keinen Sinn macht. Daher hab ich das wohl übersehen.



  • @titan99_ sagte in einfache Matrizenklasse, Vererbung:

    Ein Vorteil wäre, dass unterschiedliche Spaltenanzahlen je Reihe möglich wären. Aber von solchen Matrizen habe ich noch nie gehört.

    Ja, da habe ich dann, wenn nichts anderes vorgegeben, den ersten Vector als Spaltenanzahl genommen und sonst auch gar nicht auf Größe geachtet. Wenn sie reingepasst haben, wurden sie eingefügt, wenn nicht wurde der Vector abgeschnitten.

    Ich werde das aber wie gesagt, wieder zu std::vector<float> elements;ändern, wie ich es schon hatte. Gefällt mir auch besser.

    Edit: Als eine Übergabe werde ich weiterhin einen std::vector<std::vector<float>>anbieten und nach dem obigen Prinzip einfügen. Um zu Testzwecken schnell Daten übergeben zu können, finde ich den praktisch.



  • @zeropage sagte in einfache Matrizenklasse, Vererbung:

    Um zu Testzwecken schnell Daten übergeben zu können, finde ich den praktisch.

    Wie soll das praktisch sein?



  • Na, zum Beispiel

    std::vector<std::vector<float>> vArray;
    
    std::vector<float> f0 = { 1., 2., 3. };
    vArray.push_back(f0);
    std::vector<float> f1 = { 4., 5., 6. };
    vArray.push_back(f1);
    std::vector<float> f2 = { 7., 8., 9. };
    vArray.push_back(f2);
    std::vector<float> f3 = { .1, .2, .3 };
    vArray.push_back(f3);
    
    Mat mt(vArray);
    mt.print("mt");
    

    Wie würdest Du denn das machen?



  • std::vector<float> vArray{ 1., 2., 3.,
                               4., 5., 6.,
                               7., 8., 9.,
                               .1, .2, .3 };
    


  • Ok, einen std::vector<>weniger geschrieben. Für was? Der Doppelvector ist doch nicht die einzige Möglichkeit zur Übergabe, nur eine von anderen.


  • Gesperrt

    std::copy

    std::vector<float> vArray;
    
    std::vector<float> f0 = { 1., 2., 3. };
    std::copy(f0.begin(), f0.end(), vArray.end())
    std::vector<float> f1 = { 4., 5., 6. };
    std::copy(f1.begin(), f1.end(), vArray.end())
    std::vector<float> f2 = { 7., 8., 9. };
    std::copy(f2.begin(), f2.end(), vArray.end())
    std::vector<float> f3 = { .1, .2, .3 };
    std::copy(f3.begin(), f3.end(), vArray.end())
    


  • Hübsche Beispiele, die alle das selbe Ergebnis haben.

    Der Doppelvektor ist doch nur deshalb irritierend, weil ich ihn in der obigen Array-Klasse als Grundlage genommen habe. Aber das ist doch hinfällig. Gibt es nicht mehr.

    Edit: Verstehe aber, was Ihr meint. Wenn die Klasse umgeschrieben ist, sollte man analog zur Struktur auch nur einen Vektor übergeben können. Finde es aber nicht tragisch, trotzdem auch einen Doppelvektor anzunehmen.



  • @titan99_ sagte in einfache Matrizenklasse, Vererbung:

    std::copy(f0.begin(), f0.end(), vArray.end())
    

    wth?


  • Gesperrt

    @Swordfish Sorry, dachte es geht so, den std::back_inserter braucht es anscheinend.

    std::copy(f0.begin(), f0.end(), std::back_inserter(vArray))
    
    

    Ideone



  • Bei Übergabe eines Vektor muss ich noch die Dimensionen angeben, also Mat mt(3, 4, vec);. Das entfällt auch bei einem Doppelvektor. Wie gesagt, als Eingabe, nicht als Struktur.


Anmelden zum Antworten