Benutzer mit den meisten Antworten
Performanter Datenzugriff mit Byte-Order Tausch

Frage
-
Hallo Forum
Ich möchte gerne einen hoch performanten Code für den Zugriff auf Daten mit Byte-Order-Tausch (Stichwort High-Byte-First) realisieren. Ich habe einen Zeiger des Typs unsigned char und möchte die Float-Zahl, auf die dieser Zeiger zeigt auslesen (der Zeiger ist deshalb unsigned char, weil er genausogut auf andere Datentypen zeigen könnte).
Im einfachen Fall würde ich das (für nicht C++ Freaks vermutlich unlesbar) so realisieren:
unsigned char *pData; DWORD Offset; ... return(((float*)pData[Offset])[0]);
Jetzt möchte ich aber noch die Byte-Reihenfolge umdrehen, bevor ich die Sache auf float caste. Das Umdrehen der Bytereihenfolge geht wohl am schnellsten mit dem Assembler Befehl "BSWAP". Wie kriege ich aber jetzt die Prozessorregister so in den Griff, dass er das macht, was ich will und das auch noch mit wenig Maschinenbefehlen (also schnell)?
Ich habe da eigentlich zwei Probleme:
1.) wie kriege ich den Zeiger in ein Prozessorregister
2.) wie kriege ich einen Wert im eax-Register auf float-umgecastet?
also etwa so:
float value; __asm { lea esi,pData mov eax,[esi] bswap eax mov value,eax }
Kann sowas funktionieren? Kann ich davon ausgehen, dass "mov eax,[esi]" die richtigen Daten lädt, oder kann das Datensegment falsch sein?
Kann ich das esi Register ungestraft verändern, sollte ich es mit push/pop sichern?
Grüße
Fireheart
- Bearbeitet Fire-Heart Montag, 22. Juli 2013 06:50
Antworten
-
Hallo,
vor dem Assembler würde ich es erst mal mit einem intrinsic versuchen.
Da ein float in ein ulong passt, würde hier gehen _byteswap_ulong.Siehe auch: http://stackoverflow.com/questions/105252/how-do-i-convert-between-big-endian-and-little-endian-values-in-c
Gruß Elmar
- Als Antwort markiert Fire-Heart Dienstag, 23. Juli 2013 05:33
Alle Antworten
-
Ich habe nicht genau verstanden was Du willst
Schau Dir doch den erzeugten ASM Gesamtcode an.Das ESI Register müsstest Du ohne Probleme benutzen können. Der Optimizer geht bei einem ASM Block nicht davon aus, dass alle Register unverändert blieben.
Infos findest zu ASM in der MSDN
http://msdn.microsoft.com/en-us/library/4ks26t93(v=vs.71).aspxBzgl. Register
http://msdn.microsoft.com/en-us/library/k1a8ss06(v=vs.71).aspx
Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
- Bearbeitet Martin RichterModerator Montag, 22. Juli 2013 07:20 Noch was ergänzt
-
Hi Fireheart,
1. little endian wird von der cpu vorausgesetzt...=> z.b. auf x86 CPU machst du dir keine gefallen...
2. auf jeden fall solltest du die sichern und beim verlassen wiederherstellen
Wenn du etwas in ein Register lädst ist es drinn... Du musst dafür sorgen das die richtigen daten drinnen sind...
Wenn du high performance programmieren möchtest auf einen x86 mit floats empfehle dir dich mit simd auseinanderzusetzen...
- Bearbeitet Brian Dahl Montag, 22. Juli 2013 08:53 Ergänzung
-
Hallo,
vor dem Assembler würde ich es erst mal mit einem intrinsic versuchen.
Da ein float in ein ulong passt, würde hier gehen _byteswap_ulong.Siehe auch: http://stackoverflow.com/questions/105252/how-do-i-convert-between-big-endian-and-little-endian-values-in-c
Gruß Elmar
- Als Antwort markiert Fire-Heart Dienstag, 23. Juli 2013 05:33
-
Hallo Elmar
Es war ja irgendwie klar, dass es hierzu bereits einen fertigen Befehl geben muss, nur kannte ich ihn halt noch nicht. Danke schön.
Die von mir bislang verwendete Methode:
unsigned char *pPtr; ... union { unsigned char byte[4]; float value; } h; for (int i=0; i<4;i++) h.byte[i] = pPtr[3-i]; return(h.value);
liefert eigentlich auch sehr kurzen Code (sieht nur als C sehr viel aus).
Ich habe auch ein paar Speed-Tests zu diesem Thema gemacht und festgestellt, dass ich hier wohl an der falschen Front kämpfe. Die Bearbeitungszeit von derartigen Umwandlungen (wie immer man sie auch macht) liegt im einstelligen Nanosekunden-Bereich. Ich denke, ich tue gut daran, kritischere Codestellen zu optimieren.
Grüße
FireHeart
-
Wird bei Fließkommazahlen überhaupt irgendwas geswapped? Soweit ich weiss, definiert der IEEE doch die Reihenfolge und Anzahl der Bits [Vorzeihen][Exponent][Mantisse], so dass man beim Austausch mit big-endian-Systemen da gar nichts besonderes beachten muss. Das mit dem Little-endian hat doch eher den sinn, dass wenn man zB ein DWORD mit Wert 1 im speicher hat, ein char lesen kann und dann immer noch den richtigen Wert hat.
Also wenn es nicht gerade darum geht, die Daten zu verscrambeln macht byteorder-swapping bei floats glaub ich keinen Sinn.
-
Hallo Heiko,
mal so mal so, siehe den verlinkten SO Artikel oben:
For floats and doubles it's more difficult as with plain integers as these may or not may be in the host machines byte-order. You can get little-endian floats on big-endian machines and vice versa.
Gruß Elmar
-
Hallo0 Heiko,
erst einmal sind alles nur Bytes (zumindest auf den heutigen gängigen Speichermodellen ;)
Ob die Bytes ein Integer, Fließkommazahl, ein (Text-)Zeichen darstellt, steht nirgendwo.
Sobald mehr als zwei Bytes gebraucht werden kommt es darauf an, wie die Byte Reihenfolge interpretiert wird. Auch IEEE-754 hält sich da heraus: http://stackoverflow.com/questions/5242589/would-float-point-format-be-affected-by-big-endian-and-little-endian
Gruß Elmar
-
Mag ja sein, dass das da so steht. Aber die Reihenfolge der BITS ist das definierte. Insofern die Reihenfolge der Bits in einem float SEEEEEEEEMMMMMMMMMM... IST, bekommt man bei dessen Adresse das Byte mit dem S-bit. Wie gesagt BIG und LITTLE bezieht sich auf den Stellenwert des zuerst gelesenen/geschriebenen Bytes. Macht Null Sinn in Bezug auf floats, es sei denn man schiebt sie von einem float- in ein int-register und speichert von da.
-
Das gibt 'ne Vote - klingt für mich nach Konzeptionsfehler.
Die physische Existenz der Bits auf einem Medium entspricht entweder der IEEE Reihenfolge oder nicht. Hab aber nicht nachgelesen, ob Siemens angeben, IEEE-konform zu sein.
"Beim Programmieren selbst regiert der Rotstift!..."
- Bearbeitet Heiko Lewin Mittwoch, 14. August 2013 11:45