verbesserungsvorschläge für endlich fertig gestellte klasse



  • print_at(ostream& out);

    warum kein operator<<?



  • danke ich werde deine ratschläge bis morgen umsetzen und dann die klasse/n posten.
    nur eins noch, ich weiß mit der ausgabefunktion nicht so recht viel anzufangen
    wie müsste das hier richtig aussehen 😕 :

    void matrix<T>::print_at(std::ostream& ausgabe);
    {
        //if(spalten_matr < 1)
            for(unsigned int i = 0; i < zeilen_matr; i++)
                (std::cout.ausgabe<<("Position ")).ausgabe<<(i);
                (std::cout.ausgabe<<(": ").ausgabe<<(matrix_eindim[i]);
                (std::cout.ausgabe<<(std::endl) );
        /*
        else
            {
                for(unsigned int i = 0; i < zeilen_matr; i++)
                {
                    cout<<endl;
                    for(unsigned int j = 0; j < spalten_matr; j++)
                        cout<< "Position " << i << ": " << matrix_zweidim[i][j];
                }
            }
        */
        return ausgabe;
    }
    


  • strings schrieb:

    print_at(ostream& out);

    warum kein operator<<?

    ach, den hab ich doch glatt vergessen.

    ostream& operator<<(ostream& out,Matrix const& m){
       return m.printAt(out);
    }
    

    und weil ich irgendwo sowas wie

    template<typename T>
    ostream& operator<<(ostream& out,T const& t){
       return t.printAt(out);
    }
    

    stehen habe, reicht's bei mir immer, nur eine printAt anzubieten, wenn ich eine klasse ausgebbar machen mag.



  • warum denn dann 2 methoden für die ausgabe??



  • strings schrieb:

    warum denn dann 2 methoden für die ausgabe??

    die printAt()-Methode brauchst du wenn du ein objekt polymorph ausgeben willst, virtual funktioniert leider bei normalen Funktionsaufrufen nicht.

    der template-wrapper ist ne gute idee 👍



  • Volkard du hast ja echt VIEL Zeit 😉 Und bitte_bitte_bitte verwende doch Englisch im Code wirkt viel professioneller und ist mit der Zeit besser und auch von allen in der gesamten Welt besser zu lesen.



  • T *matrix_eindim; 
            T **matrix_zweidim;
    

    Und warum machst du in einer Matrixklasse ein und zweidimensionale Matrizen. Normalerweise hast du eine Klasse Matrix2d Matrix3d Matrix4d... Was ist auch bitte eine 1dimensionale Matrix? kannst ja gleich nen float nehmen?



  • dali schrieb:

    Was ist auch bitte eine 1dimensionale Matrix? kannst ja gleich nen float nehmen?

    nee. ein float ist 0d.



  • [quote="dali"]Volkard du hast ja echt VIEL Zeit ;)[quote]
    ich habe VIEL zu wenig zeit.

    Und bitte_bitte_bitte verwende doch Englisch im Code

    das mache ich manchmal. mit welchem code haste im moment ein problem?

    wirkt viel professioneller

    ich lege nicht extrem viel wert darauf, durch irgendwas professioneller zu wirken, als ich bin. besonders im code nicht. den mache ich so gut und so lesbar unter nichtvernachlässigung von ein wenig erweiterbarkeit und performance, wie ich kann. im allgemeinen mache ich projektübergreifend wiederverwendbares auf englisch und domain-spezifisches auf deutsch. das ergibt auch eine schöne und augenfällige schichtentrenung. einfach köstlich.

    und ist mit der Zeit besser und auch von allen in der gesamten Welt besser zu lesen.

    da ich eh keine kommentare mache, ist das problem schon fast aus der welt. *g*



  • Das mit dem Englisch war eigentlich auf exigoner bezogen. Ist sicher Geschmackssache was man verwendet aber Englisch und Deutsch mixen find ich nicht gut... Und Code ohne Kommentare naja... Mir hat man immer Punkte bei den Übungen abgezogen 😉



  • So noch ein bisschen (?) Matrixdesign.

    Was willst Du eigentlich mit der Matrix machen? Ich kenne Matrizen in erster Linie aus der diskreten Mathematik oder Numerik.

    Für einen Datentyp Matrix (der in dem o.g. Kontext eingesetzt werden soll) bietet sich an:

    1.) Betreibe zuerst Matrixdesign

    Das Wichtigste. Überlege Dir zuerst ganz genau, was die Matrix können soll und "make the common case fast".

    2.) Implementiere nur den Datentyp Matrix.

    Es gibt keine "eindimensionale" oder "zweidimensionale" Matrix, in dem Sinne wie es hier verwendet wird. Eine Matrix besteht immer (!) aus Zeilen und Spalten.
    Und deswegen gibt es nur "zweidimensionale" Matrizen.
    Bsp:
    [1 0] ist eine (1x2)-Matrix
    [1 0; ist eine (2x2)-Matrix
    [0 1]
    [1] ist eine (1x1)-Matrix

    Die Dimension einer Matrix ist übrigens die Anzahl der linear unabhängigen Zeilen bzw. Spalten.

    3.) Repräsentiere den Inhalt der Matrix als doppelt verkettete Liste.

    Das mag vielleicht auf den ersten Blick wie Speicherverschwendung aussehen, ist aber tatsächlich, was übliche Matrixoperationen angeht, wesentlich effizienter. Du kannst Dir ja als Übung überlegen, warum.

    Hier nur ein paar Hinweise:
    - Hinzufügen von Zeilen/Spalten wird einfacher
    - Löschen von Zeilen/Spalten wird einfacher
    - Tauschen von Zeilen/Spalten wird einfacher
    - Transponieren wird einfacher
    - Matrix-Matrix Multiplikation wird einfacher
    - Gaussalgorithmus wird einfacher
    - Konsistenes Prüfen auf NULL-Zeiger

    4.) Wähle eine einfach Schnittstelle

    Neben Kontruktor/Destruktor muss die Matrix eigentlich nur +, -, * (und /) sowie Zeilen/Spalten Manipulationen beherrschen. Weitere Elementfunktionen würde ich nur aufnehmen wenn Du sie wirklich häufig brauchst, ansonsten auslagern.

    5.) Programmiere einfach und effizient

    Auch sehr wichtig. Ständiges Hin- und Herkopieren von irgendwelchen Werten ist ziemlich laaaaaaaangsam (stattdessen ein paar Zeiger verbiegen). Ebenso ständiges new und delete (lieber Puffer und Speicherpools verwenden). Überprüfe immer wieder, ob es nicht auch einfacher geht.

    So genug Lehrmeisterei. Das hat vielleicht sogar ein bisschen zu weit geführt, sollte Dir aber auch zeigen, dass selbst so etwas einfach Erscheinendes wie eine Matrix verdammt schwer zu implementieren ist. Aber es reicht ja schon, wenn Du einfach ein paar Ideen bekommen hast, wie Du Deine Matrixklasse verbessern
    kannst.

    Wenn jemand Spass daran hat und ein wenig Langeweile, kann sie/er ja mal versuchen eine effiziente Matrixklasse zu implementieren, die die üblichen Operationen darauf unterstützt und dann zum Beispiel an Bitmaps austesten.
    Schonmal versucht, alle Eigenvektoren einer Bitmap zu bestimmen? Oder gar zu invertieren?

    Gruss

    turing



  • die ganzen ratschläge lassen sich ja gut umsetzen, aber ich verstehe die ausgabefunktion einfach nicht.
    packe ich das in meine klasse

    std::ostream& operator<<(std::ostream& out, matrix const& m) return m.printAt(out);
    

    beomme ich fehler



  • Turing schrieb:

    3.) Repräsentiere den Inhalt der Matrix als doppelt verkettete Liste.

    Das mag vielleicht auf den ersten Blick wie Speicherverschwendung aussehen, ist aber tatsächlich, was übliche Matrixoperationen angeht, wesentlich effizienter. Du kannst Dir ja als Übung überlegen, warum.

    Hier nur ein paar Hinweise:
    [...]
    - Matrix-Matrix Multiplikation wird einfacher
    - Gaussalgorithmus wird einfacher

    Begründung?

    Was dagegen spricht:
    - Speicherverbrauch wird bei dichtbesetzten Matrizen viel höher
    - Index-Zugriffe werden langsamer

    Nene, verkettet bitte nur bei großen dünnbesetzten Matrizen.

    Im Idealfall hat man mehrere Matrixklassen in der Schublade aus denen man je nach Anwendungsfall wählen kann:
    - Eine dynamische wenn die Dimensionen erst zur Laufzeit bekannt sind.
    - Eine generische, wenn die Dimensionen zur Compilezeit feststehen.
    - Mehrere für dünnbesetzte Matrizen die verkettet, mit einer Hashtable oder ganz anders implementiert sind, je nach Aufbau der Matrix.
    - ...

    boost::ublas



  • ich werd erstmal keine verketteten listen benutzen um ne basisklasse zu schreiben, vielleicht später zum ausprobieren, aber niccht jetzt.



  • so was haltet ihr davon?, abgesehen von der ausgabe 😞

    #ifndef MATRIX_KLASSE
    #define MATRIX_KLASSE
    
    #include <iostream>
    #include <cstdlib>
    
    template <class T>
    class matrix
    {
        private:
            T **matrix_zweidim;
    
            unsigned int zeilen_array;
            unsigned int spalten_array;
    
            unsigned int index_z;
            unsigned int index_s;
    
        public:
            matrix(unsigned int z, unsigned int s);  //zwei dimemsionen
            ~matrix();
    
            T *get_matrix();
    
            void ausgabe_array();
            void push_pos(T *feld, unsigned int zeilen_array, unsigned int spalten_array, int pos_z, int pos_s); //für zweidim matrix
    };
    
    //##############################################################################
    
    template <class T>
    inline matrix<T>::matrix(unsigned int zeilen, unsigned int spalten) 
    : index_z(0), index_s(0), zeilen_array(zeilen), spalten_array(spalten)
    {
        matrix_zweidim = new T*[zeilen];
        for(int i=0; i < zeilen; i++)
            matrix_zweidim[i] = new T[spalten];
    }
    
    template <class T>
    matrix<T>::~matrix()
    {
        for(int i=0; i < zeilen_array; i++)
            delete [] matrix_zweidim[i];
        delete [] matrix_zweidim;
    }
    
    template <class T>
    T *matrix<T>::get_matrix()
    {
        return matrix_zweidim;                      
    }
    
    template <class T>
    void matrix<T>::push_pos(T *feld, unsigned int feld_zeilen, unsigned int feld_spalten, int position_zeile, int position_spalte)
    {
        for(unsigned int i = position_zeile, j = 0; i < (feld_zeilen + position_zeile); i++, j++)
            for(unsigned int k = position_zeile, l = 0; k < (feld_spalten + position_spalte); k++, l++)
                matrix_zweidim[i][k] = feld[j][l];
    
        if( (feld_zeilen + position_zeile) > index_z)
            index_z = (feld_zeilen + position_zeile);
        if( (feld_spalten + position_spalte) > index_s)
            index_s = (feld_spalten + position_spalte);       
    }
    #endif
    
    #ifndef ARRAY_KLASSE
    #define ARRAY_KLASSE
    
    #include <iostream>
    #include <cstdlib>
    
    template <class T>
    class array
    {
        private:
            T *array_eindim;
    
            unsigned int zeilen_array;
            unsigned int index_z;  //damit verwechlungen ausgeschlossen sind
    
        public:
            array(unsigned int z); //eine dimension
            ~array();
    
            T *get_array();
    
            void ausgabe_array();
            //std::ostream& operator<<(std::ostream& out, matrix const& m) return m.printAt(out);
            void push_back(T *feld, unsigned int zeilen_array); //schiebt hinten rein(matrix)
            void push_pos(T *feld, unsigned int zeilen_array, int pos_z);  //für eindim array
    };
    
    //##############################################################################
    
    template <class T>
    inline array<T>::array(unsigned int zeilen) 
    : index_z(0), zeilen_array(zeilen)
    {
        array_eindim = new T[zeilen];
    }
    
    template <class T>
    array<T>::~array()
    {
        delete [] array_eindim;
    }
    
    template <class T>
    T *array<T>::get_array()
    {
        return array_eindim;                      
    }
    
    template <class T>
    void array<T>::ausgabe_array()
    {
        for(unsigned int i = 0; i < zeilen_array; i++)
            std::cout<< "Position " << i << ": " << array_eindim[i] << std::endl;
    }
    
    template <class T>
    void array<T>::push_back(T *feld, unsigned int feld_zeilen)
    {
        for(unsigned int i = 0; i < feld_zeilen; ++i && ++index_z)
            array_eindim[index_z] = feld[i];    
    }
    
    template <class T>
    void array<T>::push_pos(T *feld, unsigned int feld_zeilen, int position_zeile)
    {
        for(unsigned int i = position_zeile, j = 0; i < (feld_zeilen + position_zeile); i++, j++)
            array_eindim[i] = feld[j];
    
        if( (feld_zeilen + position_zeile) > index_z)
            index_z = (feld_zeilen + position_zeile);
    }
    #endif
    

    ich wollts noch machen das man beim erstellen der matrix/arrays die größe beim objekt NICHT angeben brauchsondern angefangen bei einer zeile automatisch erhöht. wie kann ich das machen? kann man da einfach immer wieder "new []" aufrufen? oder muss ich da ein neuen array tmp[] erstellen?



  • @Walli:

    Es ehrt Dich, dass Du BLAS kennst und mich darauf hinweist. Aber mein Vorschlag mit den verketteteten Listen hatte nicht den Anspruch damit zu konkurrieren.

    Und sicherlich ist die Lösung mit den doppelt verketteten Listen auch nicht die beste und schnellste.
    Was aber zum Beispiel den Aufwand oder den Schwierigkeitsgrad angeht ist es meiner Meinung ein guter Kompromiss zwischen Einfachheit und Effizienz für übliche Matrixoperationen. Das kommt aber auch wieder darauf an, ob ich gerne mit Zeigern oder Indices rechne. Was einfach ist und was nicht, hängt wahrscheinlich auch sehr vom eigenem Geschmack ab.

    Und viel höher ist der Speicherverbrauch auch nicht. So etwa das Dreifache...
    Und der Gewinn? Naja, wie schon gesagt, es wird einiges einfacher.
    Okay, bei einer (1000x1000)-Matrix mit 32 Bit Einträgen wären das statt 4 MB eben 12 MB, noch erträglich finde ich. Aber spätestens bei (1000x1000)-Matrizen sollte dann auch die Grenze dessen liegen, was man "mal eben" von Hand programmieren will.

    Viel Spass noch beim Weiterdiskutieren.

    Gruss

    turing



  • ich wollte meine arrays für ein neuronales netz benutzen, ich habe noch nie verkettete listen benutzt, wären die für solche arten der anwendung effizient?



  • dali schrieb:

    Und Code ohne Kommentare naja... Mir hat man immer Punkte bei den Übungen abgezogen 😉

    Ja, aber das liegt einfach daran, dass Tutoren notorisch nicht programmieren können. Die allermeisten Kommentare die ich in Codes lese (ob nun an der Uni, im Netz oder in sonstigen Projekten), sind vollkommen sinnfrei. Wenn man ordentlichen Code schreibt, reduziert sich der zu kommentierende Teil auf ein Minimum. In meinem Fall wäre das fast ausschließlich das Kommentieren von Funktionen und Klassen im Dokumentationsstil (JavaDoc, XML, ...).



  • stimmt, die meisten kommentare sind sinnlos und helfen nur denjenigen der das prog geschrieben hat.



  • @exigoner:
    Mit neuronalen Netzen kenne ich mich leider überhaupt nicht aus. Werden die nicht auch in der Mustererkennung eingesetzt? Schreib doch einfach auf, was Du mit der Matrix konkret machen willst.

    Zu Kommentaren:
    Ich finde Kommentare schon sehr wichtig, aber auch hier gilt eindeutig die Devise, dass weniger auch mehr sein kann.


Anmelden zum Antworten