Vector Template Problem mit Normalisierung bei union type _m128
-
zu 1. cpp-Tags was sind den das?

zu 2. ja ist C, sehe da aber kein Problem drinn.
zu 3. Ja du hast vollkommen recht.
Das *= ist eigentlich die Skalarmultiplikation der Parameter ist bloss absolut falsch bennant. Natürlich kann man /= weglassen, ist wahrscheinlich auch besser für die performance.
Ich habe es extra dot (ist doch skalarprodukt auf english?) genannt. Mit einem zweiten * operator als skalar komme ich immer durcheinander. Ich denke auch das es so eindeutiger ist und man in der Benutzung nicht ausversehen einen Fehler macht indem man einen scalar statt Vector nimmt.
zu 4. Mir ist klar dass das das ( geil 3x das ) gleiche ist. Nur habe ich noch keinen operator += für einen union Typ (__m128) hinbekommen.
Danke dir schon mal werde gleich mal ein wenig abändern und es editieren.
-
Natürlich kann man /= weglassen, ist wahrscheinlich auch besser für die performance.
Würde ich nicht machen - ich würds als Skalarmultiplikation mit dem Reziprogen lassen... aber du hast als rhs ja nen TKVector - und bei ner Skalarmultiplikation sollte das ein Skalar sein - wie der Name schon sagt ^^ also T
Nur habe ich noch keinen operator += für einen union Typ (__m128) hinbekommen
was willst du machen?
ein += (auf einen vector) mit einem float?
was soll das für ne operation darstellen?außerdem: warum redest du ständig von einem union Typ __m128? (__x sollte so und so für den Compiler reserviert sein) - du müsstest zumindest mal sagen, was ein union typ __m128 ist... und dann zeigst du noch mal genau das stück code, was jetzt nicht so will, wie es soll ^^
bb
-
Hey, ich habe die cpp-tags gefunden

Habe oben mal die Änderungen gemacht. Hoffe das haut soweit alles hin.
Ich möchte sowas hier machen:
TKVector<__m128, 3> test; ... normalize(test)Ich nutze die SSE Befehlserweiterungen. Dabei gibt es einen Typ der heißt __m128, der folgendermaßen definiert ist in xmmintrin.h
typedef union __declspec(intrin_type) _CRT_ALIGN(16) __m128 { float m128_f32[4]; unsigned __int64 m128_u64[2]; __int8 m128_i8[16]; __int16 m128_i16[8]; __int32 m128_i32[4]; __int64 m128_i64[2]; unsigned __int8 m128_u8[16]; unsigned __int16 m128_u16[8]; unsigned __int32 m128_u32[4]; } __m128;Mein Problem ist das normalize nicht geht weil ich die 1 nicht in den Typ __m128 umwandeln kann.
Und es geht auch dot nicht weilich noch nicht rausgefunden habe wie ich einen += operator für diesen Typ mache.
-
Wenn du eh nen template hast, kannst du doch auch einfach die "normalen" Typen nutzen?!
template <typename T, size_t laenge> class TKVector { //... template <typename Trhs> operator += (const TKVector <Trhs, size_t laenge> &rhs) { for (size_t i(0); i != laenge; ++i) { data[i] += T(rhs[i]); } } };allerdings solltest du evtl auch eine Konvertierung von TKVector <T, l> zu TKVector <T2, l2> anbieten - und den so entstehenden Vector entsprechend mit 0en auffüllen oder einfach "abschneiden" und den Wertetyp entsprechend ändern
(macht im mathematischen ja auch durchaus Sinn), also in etwa so:template <typename T, size_t laenge> class TKVector { //... template <typename T_rhs, laenge_rhs> TKVector <T, laenge> copy (const TKVector <T_rhs, size_t laenge_rhs) &rhs) { if (laenge_rhs < laenge) { for(size_t i(0); i != laenge_rhs; ++i) { data[i] = T(rhs.data[i]); } for(size_t i(laenge_rhs); i != laenge; ++i) { data[i] = T(); //kannst auch 0 schreiben, aber ich machs immer so - in der Hoffnung, dass es besser optimiert wird ^^ } } else { for(size_t i(0); i != laenge; ++i) { data[i] = T(rhs.data[i]); } } } /*explicit - konnte ich mich noch nicht ganz entscheiden - aber eher nicht ^^*/ template <typename T_rhs, size_t laenge_rhs> TKVector(const TKVector <T_rhs, laenge_rhs> &rhs) { *this = copy (rhs); } operator += (TKVector rhs) { for (size_t i(0); i != laenge; ++i) { data[i] += rhs[i]; } } };TKVector <float, 3> eins; TKVector <int , 5> zwei; TKVector <float, 5> drei(zwei); drei += eins;sollte so weit eigtl alles logisch sein - falls nicht, frag nach ^^
bb
-
Halcom schrieb:
zu 2. ja ist C, sehe da aber kein Problem drinn.
Wenn du dir der Fehleranfälligkeit und Umständlichkeit von C-Mitteln bewusst bist und diese auch in Kauf nimmst, ist das auch kein Problem.

Oft ist es jedoch so, dass Leute gar nicht die entsprechenden Lösungen in C++ kennen. Statt
memcpy()kannst du beispielsweisestd::copy()verwenden, stattmemcmp()operator==und so weiter...Halcom schrieb:
Ich habe es extra dot (ist doch skalarprodukt auf english?) genannt.
"dot" bedeutet nur Punkt. Skalarprodukt (Punktprodukt) wäre "dot product". Vektorprodukt (Kreuzprodukt) hingegen "cross product".
Halcom schrieb:
Mit einem zweiten * operator als skalar komme ich immer durcheinander.
Für die Vervielfachung (= Multiplikation eines Vektors mit einem Skalar) würde ich schon
operator*definieren. Beim Skalarprodukt finde ich eine Funktion angebracht, da dann auch sicher klar ist, welches Produkt gemeint ist (es gibt nicht nur Skalarprodukt).Halcom schrieb:
union Typ (__m128)
Wie unskilled schon sagte, brauchst du eigentlich keine Union.
unions werden in C++ kaum eingesetzt, dafür sind sie einfach zu unsicher und können nur mit PODs arbeiten. Wenn du ein Template hast, instanziierst du das für einen bestimmten Typen (alsofloat,char,int,std::complexoder irgendwas) - da hast du ja den Typen schon, und natürlich auch dessen Typsicherheit.
-
Wie unskilled schon sagte, brauchst du eigentlich keine Union. unions werden in C++ kaum eingesetzt, dafür sind sie einfach zu unsicher und können nur mit PODs arbeiten. Wenn du ein Template hast, instanziierst du das für einen bestimmten Typen (also float, char, int, std::complex oder irgendwas) - da hast du ja den Typen schon, und natürlich auch dessen Typsicherheit.
Ich brauche ihn eben doch. Weil ich den SSE Befehlssatz nutzen möchte. Dafür gibt es bereits vorgefertigte Methoden die das Handling erleichtern.
Schaut ihr z.B. in der Hilfe mal unter _mm_mul_ps:__m128 _mm_mul_ps(__m128 a , __m128 b );
Ist da schon fertig definiert. Würde ich jetzt mein eigenen SSE2 datentyp machen könnte ich diese intrinsics nicht nutzen und müsste die implementierungen in assembler machen. Und da habe ich eigentlich nict wirklich lust drauf.
Also habe ich nur 2 Möglichkeiten. Entweder ich verabschiede mich für den Datentyp von meinem Template und mache einen spezialisierten Vektor oder aber ich mache meinen eigene SSE2 Datentyp und implementiere die operatoren eben in Assembler anstatt die intrinsics zu nutzen.
-
hmm... hab ich kein plan von - aber ich würde mal behaupten wollen, dass du dir dann das template auch gleich sparen kannst...
allerdings würde ich so was nicht machen - nen vektor ist nur so lange hilfreich, wie ich mit dem datentyp meiner wahl rechnen kann (neben den pods auch mit komplexen oder sehr großen zahlen) - und da würde dein vector dann voll durchfallen... außerdem weiß ich nicht, wie viel geschwindigkeit der sse-befehlssatz bringt - falls es sehr viel schneller ist wird es sich vll doch lohnen aber naja...falls du zeit hast, kannste ja mal zeigen, wie viel schneller er mit sse-befehlssatz rechnen kann als mit "normalem" code?
bb
-
Hallo
Ich möchte etwas ähnliches machen, da ich für einige Funktionen den Typ unterscheiden muss. Die Geschichte ist zwar ziemlicher Missbrauch von Templates, aber ich komme einfach nicht auf eine Lösung. Hat einer vielleicht ne Idee?Der Header
template<typename T> struct data<int> {typedef __m128 datentyp;}; //autsch, unzählige errors template<typename T> struct data<float> {typedef __m128i datentyp;}; //ebenso template <class T> class MyClass { union { T daten1[4]; data<T>::datentyp daten2; } ... void foo(const __m128& a, const __m128& b); void foo(const __m128i& a, const __m128i& b); ... void doSomething(const MyClass<T>& class) {foo(daten2, class.daten2);} // Hier muss ich den Typ wissen damit das richtige foo(...) aufgerufen wird };Das es beim kompilieren knallt steht außer Frage... Gibts da irgendeine Möglichkeit dies umzusetzen?
Typsicherheit ist meinerseits gegeben da nur mit int oder float das Template instanziert wird.
-
Templatespezialisierungen gehen etwas anders:
template<typename T> struct data; template<> struct data<int> { typedef __m128 datentyp; }; template<> struct data<float> { typedef __m128i datentyp; };Das richtige
foowird automatisch durch den Kompiler ausgewählt, da dieser die Datentypen kennt.Grüssli
-
Hey danke dir, ist der Hammer das es so geht!
So klappt es einwandfrei
template<typename T> struct data; template<> struct data<int> { typedef __m128 datentyp; }; template<> struct data<float> { typedef __m128i datentyp; }; template <class T> class MyClass { public: typedef typename data<T>::datentyp DatenTyp; union { T daten1[4]; DatenTyp daten2; } ... void foo(const __m128& a, const __m128& b); void foo(const __m128i& a, const __m128i& b); ... void doSomething(const MyClass<T>& class) {foo(daten2, class.daten2);} };Besser wäre es wahrscheinlich, wenn ich die entsprechenden Methoden spezialisiere, oder?
template<class T> void MyClass<T>::foo(const T& a, const _T& b){...} //Allgemein template<> void MyClass<float>::foo(const __m128& a, const __m128& b){...} // Spezialisierung float template<> void MyClass<int>::foo(const __m128i& a, const __m128i& b){...} // Spezialisierung int