Vektorrechner



  • Hallo!

    Ich sitze gerade an meiner aller ersten C++ Aufgabe und benötige etwas Hilfe.

    Die Aufgabenstellung sieht vollgendermaßen aus:

    Um Berechnungen mit n-dimensionalen Vektoren ausführen zu können, soll eine Klasse mit dem Namen Vektor geschrieben werden.
    Für die private Repräsentation sollen double-Arrays der Länge n, sowie eine Variable für die Dimension verwendet werden.

    Es soll ein Konstruktor bereitgestellt werden, der einen Nullvektor, der als Argument zu übergebenden Dimensionen erzeugt, oder aber auch ohne Argumente aufgerufen werden kann (in diesem Falle sei er dann der Default-Konstruktor mit n = 3).

    Folgende Public-Member-Funktionen sollen erzeugt werden:

    - Addition zweier Vektoren
    - Subtraktion zweier Vektoren
    - Skalarprodukt zweier Vektoren
    - Normierung eines Vektors. Für diese Funktion soll noch eine Hilfsfunktion erstellt werden, die den Betrag errechnet und die wiederrum die Funktion des Skalarprodukts zur Hilfe nimmt
    - Einlesen der Elemente eines Vektors von der Standardeingabe cin mittels des >>-Operators
    - Ausgabe eines Vektors als Zeilenvektor in der Form [a1 a2 a3 . . . an] auf das Standard- ausgabe-Objekt cout.

    Mein bisheriger Code sieht so aus:

    #include <iostream>
    #include <cmath>
    
    using namespace std;
    
    class Vektor{
    
        public:
    
        Vektor(){} // Leider keine Idee wie Konstrukter umgesetzt werden soll
    
        void addiere(double *a, double *b, unsigned int n)
        {
            double *x;
    
            for( int i=0; i<n; i++ )
            {
                x[i] = a[i] + b[i];
            }
        }
    
        void subtrahiere(double *a, double *b, unsigned int n)
        {
            double *x;
    
            for( int i=0; i<n; i++ )
            {
                x[i] = a[i] - b[i];
            }
        }
    
        void skalarprod(double *a,double *b, unsigned int n)
        {
            double erg=0;
    
            for (int i=0; i<n; i++) 
            {
                erg += a[i]*b[i];            
            }
        }
    
        void norm(double *a, unsigned int n)
        {
            double ergebnis,buf;
    
            skalarprod(a,a,n);
            ergebnis = sqrt(buf);
    
        }
    
        void normiere(double *a, unsigned int n)
        {
            double *x;
    
            for (int i=0; i<n; i++) {
                x[i]=a[i]/norm(a, n);    //double wird durch void geteilt. Andere Umsetzung vonnöten?
            }
        }
    
        void daten_eingeben()
        {
            unsigned int n;
            double v1[n];
    
            cout <<"Dimension:";
            cin >>n;
    
            for (int i=0; i<n; i++) {
                cout <<"Vektorkomponente eingeben";
                cin >>v1[i];
            }
    
        }
    
        void ausgabe()
        {
            //Keine Idee für Umsetzung
        }
    };
    
    int main() {
    	std::cout << "C++ Beispiel Vektoren:" << std::endl;
    
    	// Zwei Vektoren deklarieren 
    	Vektor v1(4), v2(4);
    
    	// Daten vom Benutzer einlesen
    	v1.daten_eingeben();
    	v2.daten_eingeben();
    
    	// Testen der Addition und Subtraktion
    	Vektor v3 = v1.addiere(v2);
    	Vektor v4 = v1.subtrahiere(v2);
    
    	// Ausgabe der Ergebnisse ueber die Funktion ausgabe
    	v3.ausgabe();
    	v4.ausgabe();
    
    	// Testen des Skalarprodukts und der Normierung
    	double skalarprodukt = v1.skalarprod(v2);
    	Vektor v5 = v4.normiere();
    
    	// Ausgabe
    	std::cout << "Skalarprodukt = " << skalarprodukt << std::endl;
    	v5.ausgabe();
    
    	// Testen der Ueberladenen Operatoren
    	v5 = v3 + v4;
    	v5.ausgabe();
    	v5 = v5 - v3;
    	v5.ausgabe();
    
    	return 0;
    
    }
    

    Das main-Programm soll so bleiben.

    Die aus meiner Sicht kritischen Bereiche habe ich kommentiert.

    Für ein paar Ratschläge wäre ich sehr dankbar 😉



  • äähm ... hm ... ja also ... *sprachlos*

    lösch alles was du über C++ gelernt hast und fang nochma von vorne an!



  • Schade 😃

    Wo liegen denn die größten Fehler? Oder ist alles Falsch?



  • Du hast den Sinn von Klassen nicht verstanden...
    Was du hast ist eine Ansammlung von Funktionen in einer Klasse.
    Klassen bestehen aus Daten und Funktionen.
    In diesem Fall hat jedes Vektorobjekt ein Double-Array, man muss es nicht an die Funktionen übergeben...
    Und das ist nur ein Fehler.



  • cpluskowski schrieb:

    Schade 😃

    Wo liegen denn die größten Fehler? Oder ist alles Falsch?

    Jo, alles. Deine Vektoren sind gar keine Objekte, die Vektoren darstellen.

    class Vektor{
        private:
            double* komponenten;
            int anzahl;
        public:
            Vektor(int anz=3)
            {
                anzahl=anz;
                komponenten=new int[anzahl];
                for(int i=0;i<anzahl;++i)
                   komponenten[i]=0;
            }
            //Kopierkonstruktor und Zuweisungsoperator supi nötig, sonst Absturz
    ...
            Vector addiere(Vector const& b)
            {
                Vector c(anzahl);
                for(int i=0;i<anzahl;++i)
                    c.komponenten[i]=komponenten[i]+b.komponenten[i];
                return c;
            }
    };
    

    Schau mal, wie weit Du mit dem Ansatz kommst. Denke es ist das, was Dein Lehrer sucht.


  • Mod

    volkard schrieb:

    for(int i=0;i<anzahl;++i)
                    c.komponenten[i]=komponenten[i]+b.komponenten[i];
    

    Da hast du dem Threadersteller aber (versehentlich?) eine fiese Fehlerquelle vorgeschlagen. Liegt natürlich ein bisschen an der doofen Aufgabenstellung 👎 , die Operationen auf möglicherweise inkompatiblen Objekten verlangt.



  • SeppJ schrieb:

    volkard schrieb:

    for(int i=0;i<anzahl;++i)
                    c.komponenten[i]=komponenten[i]+b.komponenten[i];
    

    Da hast du dem Threadersteller aber (versehentlich?) eine fiese Fehlerquelle vorgeschlagen. Liegt natürlich ein bisschen an der doofen Aufgabenstellung 👎 , die Operationen auf möglicherweise inkompatiblen Objekten verlangt.

    Ein Versehen. Welche meinste?
    Nee, ich wollte ihn nicht veralbern, seine Aufgabe ist schwer genug.

    edit: Test darauf, ob *this und b gleich groß sind, habe ich absichtlich weggelassen. es soll nur die vorgegebene main erstmal klappen.



  • Am Besten, cpluskowski würde den fertigen Code dann nochmal hier vorlegen und jemand fummelt noch ein paar Verbesserungen rein, die sich direkt anbieten würden, auch wenn sie nicht zur Abgabe notwendig sind.



  • volkard schrieb:

    Am Besten, cpluskowski würde den fertigen Code dann nochmal hier vorlegen und jemand fummelt noch ein paar Verbesserungen rein, die sich direkt anbieten würden, auch wenn sie nicht zur Abgabe notwendig sind.

    Danke sehr! Ja ich werde mich nochmal intensiv mit der Aufgabe beschäftigen und das ganze hier posten.


  • Mod

    volkard schrieb:

    edit: Test darauf, ob *this und b gleich groß sind, habe ich absichtlich weggelassen. es soll nur die vorgegebene main erstmal klappen.

    Ja, den meinte ich. Derzeit ist das Verhalten ungünstig und könnte zu sehr verwirrenden Fehlern führen, wenn die Felder hintereinander im Speicher liegen sollten. Dies wäre sogar mal ein Fall für std::logic_error (wollte ich schon immer mal sinnvoll einsetzen), da durch die Aufgabenstellung die logisch falsche Kombination der Objekte nicht von vornherein ausgeschlossen ist (wie schon gesagt: 👎 ).



  • SeppJ schrieb:

    volkard schrieb:

    edit: Test darauf, ob *this und b gleich groß sind, habe ich absichtlich weggelassen. es soll nur die vorgegebene main erstmal klappen.

    Ja, den meinte ich. Derzeit ist das Verhalten ungünstig und könnte zu sehr verwirrenden Fehlern führen, wenn die Felder hintereinander im Speicher liegen sollten. Dies wäre sogar mal ein Fall für std::logic_error (wollte ich schon immer mal sinnvoll einsetzen), da durch die Aufgabenstellung die logisch falsche Kombination der Objekte nicht von vornherein ausgeschlossen ist (wie schon gesagt: 👎 ).

    loool!
    Ja, std::logic_error führt bei mir auch ein totales Schattendasein.

    Zu früh gefreut. Ich kann nicht. Da würde ich ein assert reinschmieren.



  • ...



  • (Noch nicht für cpluskowski, das dauer noch ein paar Monate.)

    Swordfish schrieb:

    Da geht aber noch einiges.
    Die binären Operatoren würde ich immer außerhalb machen als friend.
    Und dann ist die erste weitere Aufgabe, alle Schleifen loszuwerden und statdessen passende stl-algos zu finden.
    Außerdem sind die asserts nicht Deine Aufgabe, die müssen von std::array gemacht werden.



  • Swordfish schrieb:

    Gut, daß Lehrer nicht wissen müssen was sie fordern ...

    Naja, die Aufgabe ist aber schon weit überdurchschnittlich gut, mußte zugeben.



  • ...



  • Geil.
    👍



  • Könnte man in << und >> nicht diese komischen Stream-Iteratoren nehmen? Ok, keine Not.

    copy-ctor und zuweisungsoperator droppen?

    und das mit dem dot...
    das ist ein rätsel. muss gehen irgendwie.



  • Swordfish schrieb:

    template< std::size_t const N = 3, typename T = double >
        friend std::ostream & operator *** ( std::ostream & os, vector_t< N, T > const & vector )
    

    👎 Und der ganze Mist 5 mal.
    Einfach das template weglassen (hat auch praktische Vorteile)

    friend std::ostream & operator *** ( std::ostream & os, vector_t const & vector )
    

    Dimension am besten als Memberfunktion, wäre ein Kandidat für constexpr.

    Zu Dot: inner_product?



  • volkard schrieb:

    Könnte man in << und >> nicht diese komischen Stream-Iteratoren nehmen?

    O ja, bitte. copy und copy_n. Diese ganzen Lambdas sind unnötig.


  • Mod

    volkard schrieb:

    und das mit dem dot...
    das ist ein rätsel. muss gehen irgendwie.

    So?

    friend T dot( vector_t const & lhs, vector_t const & rhs )
        {
            return std::inner_product( lhs.data.begin(), lhs.data.end(), rhs.data.begin(), T() );
        }
    

    Mit varidic Templates kann man sich die Algortihmen allerdings auch sparen

    #include <cstddef>
    #include <cmath>
    #include <iostream>
    #include <initializer_list>
    
    template < std::size_t... i >
    struct index_list;
    
    template < std::size_t N, typename = index_list<> >
    struct make_index_list;
    
    template < std::size_t N, std::size_t... i>
    struct make_index_list< N, index_list< i... > >
        : make_index_list< N - 1, index_list< 0, 1 + i... > >
    {
    };
    
    template < std::size_t... i>
    struct make_index_list< 0, index_list< i... > >
    {
        typedef index_list< i... > type;
    };
    
    struct expression_sequence
    {
        template < typename... T >
        expression_sequence( T&&... )
        {
        }
    };
    
    template< std::size_t const N = 3, typename T = double, typename indexes = typename make_index_list< N >::type >
    class vector_t;
    
    template< std::size_t const N, typename T, std::size_t... i >
    class vector_t< N, T, index_list< i... > >
    {
        friend std::ostream & operator<<( std::ostream & os, vector_t const & vector )
        {
            os << "[ ";
            expression_sequence{ os << vector[ i ] << ' ' ... };
            os.put( ']' );
    
            return os;
        }
    
        friend std::istream & operator>>( std::istream & is, vector_t< N, T > & vector )
        {
            expression_sequence{ is >> vector[ i ] ... };
            return is;
        }
    
        friend constexpr vector_t operator+( vector_t const & lhs, vector_t const & rhs )
        {
            return { { lhs[ i ] + rhs[ i ] ... } };
        }
    
        friend constexpr vector_t operator-( vector_t const & lhs, vector_t const & rhs )
        {
            return { { lhs[ i ] - rhs[ i ] ... } };
        }
    
        friend T dot( vector_t const & lhs, vector_t const & rhs )
        {
            T result[] = { 0., result[ i ] + lhs[ i ] * rhs[ i ] ... };
            return result[ N ];
        }
    
        public:
            static constexpr std::size_t get_dimension() { return N; }
    
            constexpr T const & operator[]( std::size_t const index ) const
            {
                return data[ index ];
            }
    
            T magnitude() const
            {
                return std::sqrt( dot( *this, *this ) );
            }
    
            vector_t norm() const
            {
                T const mag = magnitude();         
                return { data[ i ] / mag ... };
            }
    
            T data[N];
    };
    

Anmelden zum Antworten