none
Performanter Datenzugriff mit Byte-Order Tausch RRS feed

  • 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
    Montag, 22. Juli 2013 06:29

Antworten

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).aspx

    Bzgl. Register
    http://msdn.microsoft.com/en-us/library/k1a8ss06(v=vs.71).aspx


    Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de


    Montag, 22. Juli 2013 07:19
    Moderator
  • 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
    Montag, 22. Juli 2013 08:39
  • 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
    Montag, 22. Juli 2013 10:30
  • 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

    Dienstag, 23. Juli 2013 05:33
  • 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.

    Donnerstag, 25. Juli 2013 07:19
  • 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

    Donnerstag, 25. Juli 2013 09:22
  • Was soll denn da ein Byte sein? Einfach die Größe des Speicherplatzes? Also ist ein float: |Mantissa||Mantissa||MantissaExp|ExpSign| da LITTLE oder BIG endian? Die Worte machen keinen Sinn...

    Donnerstag, 25. Juli 2013 09:35
  • 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
    Donnerstag, 25. Juli 2013 09:49
  • 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. 
    Donnerstag, 25. Juli 2013 10:00
  • Hallo Heiko,

    auch bei einem Integer sind die Bits durchnummeriert 2^0 .... 2^31.
    Nur wo sie im Speicher ihr Plätzchen finden ist damit nicht gesagt ;)

    Gruß Elmar

    Donnerstag, 25. Juli 2013 12:00
  • Ja, ich bin auch echt gespannt, ob zB Typed-Arrays in Javascript ein Exponent-Byte als höherwertig wie ein Mantissen-Byte befinden oder nicht... Ich bin grad zu faul, die spec zu lesen... ;)
    Donnerstag, 25. Juli 2013 12:11
  • Hallo Heiko

    Ich hab mittlerweile vielmals IEEE float Zahlen an Siemens S7 PLCs gesendet und ich musste sie definitiv immer in der Bytereihenfolge vertauschen, damit es funktioniert hat.

    Grüße

    FireHeart

    Mittwoch, 14. August 2013 09:06
  • 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
    Mittwoch, 14. August 2013 11:42