Vektorrechner


  • 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];
    };
    


  • ...



  • ...



  • Möglicherweise die variadischen Templates?



  • ...



  • Das geht schief, wenn T nicht implizit zu double konvertierbar ist (z.B. std::complex):

    T magnitude() const 
            { 
                return std::sqrt( dot( *this, *this ) ); 
            }
    

    Besser:

    T magnitude() const 
            { 
                using std::sqrt;
                return sqrt( dot( *this, *this ) ); 
            }
    


  • Swordfish schrieb:

    No-na? Welcher Aspekt davon? Was könnte man evtl vc++-tauglich umschreiben?

    Die kompletten veriadischen Templates. Deswegen würde ich auch als Sprachfetischist keinen VC++ sondern eher clang nehmen. 😉



  • Ähm.

    double norm()
        {
            double buf = skalarprod(*this);
            double erg = sqrt(buf);
            return erg;
        }
    

    Sieht aber echt ulkig aus. 🤡
    Ich schiebe die Schuld dafür mal auf die Aufgabenstellung.



  • ...


  • Mod

    Diese Version scheint mit Visual C++ ctp zu funktionieren

    #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< i..., sizeof...(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 ] << ' ' ... };
    		bool dummy[] = { os << vector[ i ] << ' ' ... };
            os.put( ']' );
    
            return os;
        }
    
        friend std::istream & operator>>( std::istream & is, vector_t< N, T > & vector )
        {
    //        expression_sequence{ is >> vector[ i ] ... };
    		bool dummy[] = { is >> vector[ i ] ... };
            return is;
        }
    
        friend vector_t operator+( vector_t const & lhs, vector_t const & rhs )
        {
    		vector_t result = { lhs[ i ] + rhs[ i ] ... };
    		return result;
        }
    
        friend vector_t operator-( vector_t const & lhs, vector_t const & rhs )
        {
    		vector_t result = { lhs[ i ] - rhs[ i ] ... };
    		return result;
        }
    
        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 std::size_t get_dimension() { return N; }
    
            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();   
    			vector_t result = { data[ i ] / mag ... };
    			return result;
            }
    
            T data[N];
    };
    
    int main()
    {
    	vector_t<3> a = { 0, 1, 2 }; std::cout << "a = " << a << '\n';
    	vector_t<3> b = { 1, 0, 3 }; std::cout << "b = " << b << '\n';
    	auto c = a + b; std::cout << "c = " << c << '\n';
    	auto d = a - b; std::cout << "d = " << d << '\n';
    	auto e = b.norm(); std::cout << "e = " << e << '\n';
    }
    

    Unterstützung von Listinitialisierung ist noch rudimentär. U.a. wird 8.5.4/4 nicht unterstützt, so dass die expression_sequence-Variante bei diesem Compiler in der falschen Reihenfolge abgearbeitet wird.



  • Ich habe hier nochmal meinen überarbeiteten Code

    #include <iostream>
    #include <cmath>
    
    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; 
        } 
    
        Vektor addiere(Vektor const& b) 
        { 
            Vektor c(anzahl); 
            for(int i=0;i<anzahl;++i) 
                c.komponenten[i]=komponenten[i]+b.komponenten[i]; 
            return c; 
        } 
    
        Vektor subtrahiere(Vektor const& b) 
        { 
            Vektor c(anzahl); 
            for(int i=0;i<anzahl;++i) 
                c.komponenten[i]=komponenten[i]-b.komponenten[i]; 
            return c; 
        } 
    
        Vektor skalarprod(Vektor const& b)
        {
            double erg=0;
    
            Vektor c(anzahl);
            for(int i=0;i<anzahl;++i) 
                erg += komponenten[i]*b.komponenten[i];
    
            return erg;
        }
    
        double norm() 
        { 
            double buf = skalarprod(*this); 
            double erg = sqrt(buf); 
            return erg; 
        }
    
        Vektor normiere(Vektor const& b)
        {
            double buf = norm(b);
    
            Vektor c(anzahl); 
            for(int i=0;i<anzahl;++i) 
                c.komponenten[i]=b.komponenten[i] / buf; 
            return c; 
    
        }
    
        Vektor daten_eingeben()
        {
            for (int i=0; i<n; i++) { 
                std::cout <<"Vektorkomponente eingeben: "; 
                sin >>v[i]; 
            } 
    
        }
    
        void ausgabe()
        {
            for (int i=0; i<anzahl; ++i) {
            printf("[%f\n]", komponenten[i]);
            }
    
        }
    
    };
    
    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; 
    
    }
    

    Wäre nett wenn ihr mir noch ein paar Verbesserungsvorschläge geben könntet. Ich finde langsam siehts nach c++ aus 😃

    Übrigens danke für die Programme, die ihr gepostet habt, aber leider sind die noch etwas zu hoch für mich und mein Compiler (QT-Creator) mag die irgendwie nicht.



  • Hattet ihr Copy-Konstruktor/Zuweisungsoperator schon?
    Vermutlich nicht, da ihr keine Operatorüberladung kennt.
    Weil das ist die einzige Schwachstelle im Code, der Absturz bei Copy (genaugenommen beim Zerstören).
    Oh, ich sehe gerade, dass du keinen Destruktor hast. Hattet ihr den schon?
    Dürft ihr dafür std::vector verwenden, dann hast du diese Probleme nicht?



  • cpluskowski schrieb:

    Wäre nett wenn ihr mir noch ein paar Verbesserungsvorschläge geben könntet.

    Es compiliert doch noch nicht.



  • Nathan schrieb:

    Hattet ihr Copy-Konstruktor/Zuweisungsoperator schon?
    Vermutlich nicht, da ihr keine Operatorüberladung kennt.
    Weil das ist die einzige Schwachstelle im Code, der Absturz bei Copy (genaugenommen beim Zerstören).
    Oh, ich sehe gerade, dass du keinen Destruktor hast. Hattet ihr den schon?
    Dürft ihr dafür std::vector verwenden, dann hast du diese Probleme nicht?

    Probleme? Erstmal schauen, ob es so auch geht.



  • Ja, ich hatte das nur überflogen.
    Er soltle natürlich erst die Fehler ausbügeln und dafür evtl. das Design ändern.



  • Zum Laufen bekomme ich es leider nicht. Meine Bitte um Verbesserungsvorschläge war wahrscheinlich die falsche Wortwahl.

    Also ich kommentiere jetzt die Zeilen die grotesk erscheinen.

    #include <iostream>
    #include <cmath>
    
    class Vektor{ 
    private: 
        double* komponenten; 
        int anzahl; 
    public: 
        Vektor(int anz=3) 
        { 
            anzahl=anz; 
            komponenten=new int[anzahl]; //Das hier ist der Ansatz den mir Volkard vorgeschlagen hat, leider wird als Warnung angezeigt: "Assigning do 'double *' from incompatible type 'int *'"  
            for(int i=0;i<anzahl;++i) 
                komponenten[i]=0; 
        } 
    
        Vektor addiere(Vektor const& b) 
        { 
            Vektor c(anzahl); 
            for(int i=0;i<anzahl;++i) 
                c.komponenten[i]=komponenten[i]+b.komponenten[i]; 
            return c; 
        } 
    
        Vektor subtrahiere(Vektor const& b) 
        { 
            Vektor c(anzahl); 
            for(int i=0;i<anzahl;++i) 
                c.komponenten[i]=komponenten[i]-b.komponenten[i]; 
            return c; 
        } 
    
        Vektor skalarprod(Vektor const& b)
        {
            double erg=0;
    
            Vektor c(anzahl);
            for(int i=0;i<anzahl;++i) 
                erg += komponenten[i]*b.komponenten[i];
    
            return erg;
        }
    
        double norm() 
        { 
            double buf = skalarprod(*this); // "No viable conversion from 'Vektor' to 'double' / benötige ich hier einen zusätlichen header?
            double erg = sqrt(buf); 
            return erg; 
        }
    
        Vektor normiere(Vektor const& b)
        {
            double buf = norm();
    
            Vektor c(anzahl); 
            for(int i=0;i<anzahl;++i) 
                c.komponenten[i]=b.komponenten[i] / buf; 
            return c; 
    
        }
    
        Vektor daten_eingeben()
        {
            for (int i=0; i<anzahl; i++) { 
                std::cout <<"Vektorkomponente eingeben: "; 
                sin >> c.komponenten[i]; // Hier hapert es leider auch an der Umsetzung, aber die Eingabe von Daten in einer Funktion durchblicke ich nicht ganz
            } 
    
        }
    
        void ausgabe()
        {
            for (int i=0; i<anzahl; ++i) {
            printf("[%f\n]", komponenten[i]);
            }
    
        }
    
    };
    
    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; 
    
    }
    

    Könnt ihr mir Tipps geben wie ich so langsam ans Ziel gelange?

    @Nathan
    Ja, wir dürfen alles verwenden. Das Problem ist, dass wir auf uns allein gestellt sind und uns leider nichts vorgekaut wurde.


  • Mod

    Vektor(int anz=3)
    

    sollte explicit sein:

    explicit Vektor(int anz=3)
    

    dann funktioniert das return in

    Vektor skalarprod(Vektor const& b)
        {
            double erg=0;
    
            Vektor c(anzahl);
            for(int i=0;i<anzahl;++i) 
                erg += komponenten[i]*b.komponenten[i];
    
            return erg;
        }
    

    nicht mehr, weil der Rückgabetyp auch tatsächlich Unfug ist. Wird das korrigiert, gibt es auch kein Problem mit norm mehr.

    double* komponenten;
    ...
            komponenten=new int[anzahl];
    

    deklarierter Typ und der Typ von new passen nicht recht zusammen.


  • Mod

    Fällt dir nichts auf, wenn du die Zeilen 6 und 12 anguckst?

    Zeile 34: Was ist denn das Ergebnis eines Skalarprodukts für eine Art von mathematischen Objekt?

    Zeile 67: Was soll das sin sein? Woher soll es kommen? Der Compiler weiß es nicht, er kann auch nicht in deinen (oder volkards) Kopf gucken, was gemeint ist. Du musst ihm alles genau erklären.



  • Danke 🙂 new int habe ich gegen new double ausgetauscht.

    Aber beim Skalarprodukt weiß ich noch nicht ganz was ihr meint, denn ich summiere ja die Produkte der einzelnen Vektorkomponenten und das ist ja ein double -Wert oder täusche ich mich?

    Für daten_eingabe habe ich jetzt:

    Vektor daten_eingeben()
        {
            Vektor c(anzahl);
            for (int i=0; i<anzahl; i++) { 
                std::cout <<"Vektorkomponente eingeben: "; 
                std::cin >> c.komponenten[i];         } 
    
        }
    

    Ist das so besser?


  • Mod

    cpluskowski schrieb:

    Aber beim Skalarprodukt weiß ich noch nicht ganz was ihr meint, denn ich summiere ja die Produkte der einzelnen Vektorkomponenten und das ist ja ein double -Wert oder täusche ich mich?

    Das beschreibst du richtig. Aber dein Programm passt nicht zu der Beschreibung.

    Für daten_eingabe habe ich jetzt:

    Vektor daten_eingeben()
        {
            Vektor c(anzahl);
            for (int i=0; i<anzahl; i++) { 
                std::cout <<"Vektorkomponente eingeben: "; 
                std::cin >> c.komponenten[i];         } 
            
        }
    

    Ist das so besser?

    Was passiert denn mit c in Zeile 8?


Anmelden zum Antworten