16Bit Zahlen ohne Wrap-around addieren bzw. subtrahieren
-
Nicht wirklich.
-
Hört sich nach einer idealen Aufgabe für MMX und Konsorten an. Falls das für dich in Frage kommt. Damit könntest du bis zu 4 Additionen bzw. Subtraktionen gleichzeitig durchführen und kriegst die gewünschte Saturation geschenkt.
http://webster.cs.ucr.edu/AoA/Windows/HTML/TheMMXInstructionSet.html
-
TactX schrieb:
Nicht wirklich.
naja, n versuch wars wert.
-
0x1U + 0xFFFFU = 0x10000U
edit: Du editierst zu schnell
-
und du antwortest zu schnell
-
TactX schrieb:
uint16_t add(uint16_t a, uint16_t b){ uint32_t tmp; tmp = (uint32_t)a + (uint32_t)b; if( tmp >> 16 ){ return UINT16_MAX; } else{ return (uint16_t)tmp; } }
das finde ich einfacher:
uint16_t add (uint16_t a, uint16_t b) { if ((uint16_t)(a+b) < a) return UINT16_MAX; return a+b; }
btw: TactX, gewöhn' dir mal diese hässliche positionierung der '{' ab
-
ten schrieb:
btw: TactX, gewöhn' dir mal diese hässliche positionierung der '{' ab
Das nennt sich Stil, mann Stil
-
TactX schrieb:
ten schrieb:
btw: TactX, gewöhn' dir mal diese hässliche positionierung der '{' ab
Das nennt sich Stil, mann Stil
es sieht aber ziemlich unleserlich aus. etwas grössere codes in diesem stil kann ich gar nicht entziffern und muss die immer umformatieren.
~hey, wieso hast du den flamethread 'c besser als c++' geschlossen? c++ ist dreck. das weisst du auch. wir sind auf der selben seite, mann!!! ...und groovy ist ein lustiger diskussionspartner...~
-
ten schrieb:
es sieht aber ziemlich unleserlich aus. etwas grössere codes in diesem stil kann ich gar nicht entziffern und muss die immer umformatieren.
Heul doch
ten schrieb:
~hey, wieso hast du den flamethread 'c besser als c++' geschlossen? c++ ist dreck. das weisst du auch. wir sind auf der selben seite, mann!!! ...und groovy ist ein lustiger diskussionspartner...~
Ich bin Mod, das solltest du eigentlich wissen
-
TactX schrieb:
Ich bin Mod, das solltest du eigentlich wissen
klar, aber ich finde du bist etwas zu übereifrig.
hau' doch erstmal 'ne warnung raus z.b. dass beiträge, die mit dem threadthema nix zu tun haben gelöscht werden oder so.
wenn einer schon gezielt fragt nach 'was ist besser, c++ oder C', dann finde ich ist ein schliessen des threads nach dem 4ten posting etwas zu vorschnell.
noch nicht mal der OP hat dann 'ne chance, sich zu äussern
-
ten schrieb:
TactX schrieb:
Ich bin Mod, das solltest du eigentlich wissen
klar, aber ich finde du bist etwas zu übereifrig.
Danke
-
Hallo,
vielen Dank für die vielen Vorschläge :-). Ich bin am überlegen, ob ich die MMX variante ausprobieren soll, wenn gleich mir dieser Weg auch am schwersten erschein, da ich noch nie MMX Befehle verwendet habe. Jedoch muß ich diese Addition/Subtraktion immer bei 3 Farben gleichzeitig durchführen, dafür würde sich MMX, wenn ich das richig verstanden habe, am besten eigenen.
Gib es irgendwelche Gründe nicht MMX zu verwenden? (e.g. Wie sieht's dabei mit der Prozessorkompatibilität aus?)
Kennt jemand ein gutes Beispiel zum addieren von 4 word typen?Vielen Dank für Eure Antworten,
Matthias
-
mgarza schrieb:
Kennt jemand ein gutes Beispiel zum addieren von 4 word typen?
im prinzip geht das so:
1. die beiden unteren 32 bit wörter addieren -> unterer teil des ergebnisses
2. überlauf dieser addition merken (0 oder 1).
3. die beiden oberen 32 bit wörter und das überlaufbit addieren -> oberer teil des ergebnissesdie berechnung des überlaufbits in C (wenn man keinen zugriff auf's flagregister der cpu hat) kann man so machen:
// funktion mit den low-parts beider summanden aufrufen unsigned long carry (unsigned long a, unsigned long b) { return ((a & b) | ((a | b) & ~(a+b)))>>31; }
-
Hi
[quote="ten"]mgarza schrieb:
Kennt jemand ein gutes Beispiel zum addieren von 4 word typen?
Sorry, ich hätte mich besser ausdrücken sollen. Ich meinte eigentlich:
Kennt jemand ein gutes Beispiel wie man 4 16Bit Datentypen mit Hilfe der MMX Technik ohne wrap around addieren kann.
Ich vermute man muß den Befehl paddusw verwenden. Mir ist nur nicht ganz klar wie ich das mache.
Derzeit sieht das Programm etwas so aus (Ich hab leider das genaue Programm nicht vor mir liegen):
typedef struct BGR {
unsigned short b;
unsigned short g;
unsigned short r
}for(x=0;x<Width;x++){
for(y=0;y<Height;y++){
Buf[x+Width*y].r=addsaturated(Buf[x+Width*y].r,Org[x+Widthy].r);
Buf[x+Width*y].g=addsaturated(Buf[x+Width*y].g,Org[x+Widthy].g);
Buf[x+Width*y].b=addsaturated(Buf[x+Width*y].b,Org[x+Width*y].b);
}
}Lg,
Matthias
-
Das funktioniert in etwa so:
void addSaturated(u16 *dest, const u16* src, u32 len) { assert((len&3)==0); // muss durch 4 teilbar sein __asm { emms // mmx-register vorbereiten mov ecx, len mov esi, src mov edi, dest shr ecx, 2 // durch 4 teilen, wir bearbeiten qwords l0: movq mm0, [edi] // dest[ecx*4] in mmx-register 0 movq mm1, [esi] // src[ecx*4] in mmx-register 1 paddusw mm0, mm1 // packed add of unsigned saturated words, summe in mm0 movq [edi], mm0 // summe in dest schreiben add edi, 8 // nächstes qword aus dest add esi, 8 // nächstes qword aus src dec ecx // zähler verringern jnz l0 // weiter kopieren, wenn werte übrig emms // mmx-register als unbenutzt markieren } }
Diese Routine addiert die Werte aus src zu dest hinzu. Ein Überlauf findet nicht statt, d. h. die Werte werden bei 0xffff geclampt. Das ist eine ganz naive, nicht sehr flexible Implementierung, die noch optimiert werden könnte. Meine asm-Skills sind etwas eingerostet. Es sollte aber ausreichen, um das Prinzip zu verstehen.
Bezgl. der Prozessorunterstützung: MMX ist auf jedem halbwegs modernen Consumer-PC verfügbar (wurde damals mit dem Pentium 233 eingeführt).
Lass mich wissen, wie viel diese Routine bringt
-
Ich würde ja eher auf intrinsics statt auf inline assembler setzen.
-
TactX schrieb:
Ich würde ja eher auf intrinsics statt auf inline assembler setzen.
Wenn es im konkreten Fall wichtigeres als bestmögliche Ausführungsgeschwindigkeit gibt, kann man das durchaus tun. Überzeugende Vorteile sehe ich allerdings nicht.
-
pock schrieb:
TactX schrieb:
Ich würde ja eher auf intrinsics statt auf inline assembler setzen.
Wenn es im konkreten Fall wichtigeres als bestmögliche Ausführungsgeschwindigkeit gibt, kann man das durchaus tun.
Wie kommst du darauf, dass deine selbsgeschriebene Funktion zwangsläufig schneller ist als die des Herstellers?
pock schrieb:
Überzeugende Vorteile sehe ich allerdings nicht.
Sich nicht mit Assembler rumschlagen zu müssen ist für mich ein sehr überzeugender Vorteil.
-
TactX schrieb:
Wie kommst du darauf, dass deine selbsgeschriebene Funktion zwangsläufig schneller ist als die des Herstellers?
Naja, nicht zwangsläufig. Ich habe mir nicht die Mühe gemacht, den asm-Output zu vergleichen. Aber da _mm_adds_pu16 pro Aufruf 4 Words addiert, meine Funktion aber beliebig viele (mit (potenziell) minimalem Overhead), unterstelle ich einfach mal, dass ein Optimizer das wohl nur schwerlich so effizient hinkriegen wird.
Den Beweis bleibe ich schuldig, so sehr interessiert es mich dann doch nicht.
Sich nicht mit Assembler rumschlagen zu müssen ist für mich ein sehr überzeugender Vorteil.
Das kann man sehen, wie man will. Ich "schlage" mich nicht mit Assembler rum, sondern setze es dort gewinnbringend ein, wo es sinnvoll ist.
Der OP wollte ein Beispiel, nun hat er eins. Wie er es dann konkret umsetzt, ist seine Sache. Die Intrinsics sind für ihn vorerst vielleicht besser geeignet, insofern gebe ich dir Recht.
Letztendlich sind es aber trotzdem nur Wrapper über MMX-Opcodes, der fertige Code wird also ohnehin nicht weit von Assembler entfernt sein.
-
Hallo,
vielen dank für die super Routine :-), ich werde das heute Abend gleich mal ausprobieren. Wenn ich es schaffe, versuche ich auch mal die Funktion als "intrinsic" einzusetzen und die beiden gegenüber zu stellen.Noch eine kleine Frage zum Verständnis (Für mich als Newbie):
Die Pointer "u16 *dest und u16* src" sind 4*16Bit, oder?Lg und vielen Dank,
Matthias