Bin mit Funktion unzufrieden
-
volkard schrieb:
inline unsigned short rgba2rgb (unsigned long value){ //value wird hoffentlich in eax landen *grins* *(unsigned short)&value<<=2; value<<=6; *(unsigned short)&value<<=3; value>>=11; return value; }
Lässt sich nicht compilieren:
main.cpp(39) : error C2100: illegal indirection
main.cpp(39) : error C2106: '<<=' : left operand must be l-value
main.cpp(41) : error C2100: illegal indirection
main.cpp(41) : error C2106: '<<=' : left operand must be l-value
-
volkard schrieb:
oh, eins fällt mir auf.
return (((b%32) + ((g%64) << 6) + ((r%32) << 11)));
evtl ist folgendes besser
return (((b%32u) + ((g%64u) << 6) + ((r%32u) << 11)));
weil beim modulo-rechnen mit negativen zahlen immer was seltsam ist.Blöde aber für mich interessante Frage: Wie kann mit negativen Zahlen gerechnet werden wenn 'value' ein unsigned ist? *kratz und grübel*
-
''' schrieb:
volkard schrieb:
oh, eins fällt mir auf.
return (((b%32) + ((g%64) << 6) + ((r%32) << 11)));
evtl ist folgendes besser
return (((b%32u) + ((g%64u) << 6) + ((r%32u) << 11)));
weil beim modulo-rechnen mit negativen zahlen immer was seltsam ist.Blöde aber für mich interessante Frage: Wie kann mit negativen Zahlen gerechnet werden wenn 'value' ein unsigned ist? *kratz und grübel*
b war ein unsigned char. und 32 ein int.
dann macht er den b auch erstmal zu nem int.
du weißt zwar, daß nu in dem neuen int, der den wert von b hat, was nicht-negatives stehen sollte. aber der compiler verfolgt gewöhnlich sowas nicht.
also erzeugt er den asm-code für int opertator%(int,int).
-
''' schrieb:
Lässt sich nicht compilieren:
main.cpp(39) : error C2100: illegal indirection*(unsigned short*)&value<<=2;
-
verstehe! vielen dank
Und was ist mit dem Code der nicht compiliert werden kann wegen l-value? (was immer das auch ist?)
-
volkard schrieb:
inline unsigned short rgba2rgb (unsigned long value){ //value wird hoffentlich in eax landen *grins* *(unsigned short)&value<<=2; value<<=6; *(unsigned short)&value<<=3; value>>=11; return value; }
vielleicht sollte man stattdessen schreiben
inline unsigned short rgba2rgb (unsigned long value){ union{ struct{ unsigned short ax; unsigned short unused; }; unsigned int eax; } data; //data wird hoffentlich in eax landen *grins* data.eax=value; data.ax<<=2; data.eax<<=6; data.ax<<=3; data.eax>>=11; return data.eax; }
und hoffen, daß er die beiden zuweisungen wegoptimiert. falls er das tut, wäre der code wenigstens einigermaßen hübsch zu lesen.
-
volkard schrieb:
vielleicht sollte man stattdessen schreiben
inline unsigned short rgba2rgb (unsigned long value){ union{ struct{ unsigned short ax; unsigned short unused; }; unsigned int eax; } data; //data wird hoffentlich in eax landen *grins* data.eax=value; data.ax<<=2; data.eax<<=6; data.ax<<=3; data.eax>>=11; return data.eax; }
... oder gleich Inline-Assembler verwenden
-
''' schrieb:
Und was ist mit dem Code der nicht compiliert werden kann wegen l-value? (was immer das auch ist?)
Mit einem reinterpret_cast geht es:
inline unsigned short rgba2rgb (unsigned long value) { *(reinterpret_cast <unsigned short*> (&value)) <<= 2; value<<=6; *(reinterpret_cast <unsigned short*> (&value)) <<= 3; value>>=11; return (value); }
Moritz
-
wozu eigentlich die obsession mit eax ? inline funktionen haben keine bestimmte parameterkonvention. ausserdem sind unnamed structs kein standard
andererseits ist der code auf big endian systemen nat. sowieso kaputt.
hier noch eine eher esoterische variante:inline unsigned short rgba2rgb (unsigned value){ unsigned g = value; value &= 0x00f800f8u; g &= 0x0000fc00u; value >>= 3; g <<= 11; value *= 0x04000001u; value |= g; value >>= 16; return value; }
allerdings zerlegt gcc die multiplikation wieder, so dass der maschinencode im prinzip mit dem vorherigen ansatz übereinstimmt.
-
audacia schrieb:
... oder gleich Inline-Assembler verwenden
wie soll das denn gehen?
-
++++++++++++++ schrieb:
audacia schrieb:
... oder gleich Inline-Assembler verwenden
wie soll das denn gehen?
z.b. so (das dürfte allerdings schlechter als der compiler-code sein, insbes. auf willamette/northwood):
inline unsigned short rgba2rgb (unsigned value){ asm( "shrl $3,%[value]\n\t" "shlw $2,%[value]\n\t" "shll $6,%[value]\n\t" "shlw $3,%[value]\n\t" "shrl $11,%[value]" : [value] "+r" ( value ) ); return (value); }
der assembler wird hier zwei warnungen wegen falscher operandengrösse liefern, die man ignorieren kann.
bleibt noch anzumerken, dass man aus der funktion selbst wahrscheinlich nicht viel herausholen kann, allerdings wird sie wohl in der regel nicht mit einzelwerten sondern mit vielen werten eines bildes gefüttert werden, und dann sind andere möglichkeiten zur optimierung gegeben. diese funktion lässt sich ja sehr leicht und bequem vektorisieren.