Double zerlegen in M und E



  • Hallo

    ich möchte einen double über den Socket versenden und suche nach einer performanten und vor allem kompatiblen Variante den Double sauber in Mantisse und Exponent zu zerlegen um sie getrennt voneinander als INT zu versenden.

    Dabei gehts mir vor allem darum, dass die Möglichkeit besteht, dass meine Empfänger auf unterschiedlichen Plattformen und Systemen residieren und daher
    ein double nicht immer zwangsläufig eine identische Repräsentation im Speicher haben muss.

    Daher meine Idee, Mantisse und Exponent zu ermitteln und diese als INT zu versenden und im Empfänger dann wieder "zusammenzubauen".

    Jemand ne performante Idee?



  • It0101 schrieb:

    Jemand ne performante Idee?

    Problem verschieben, bis wirklich mal jemand ieee-754 nicht versteht.
    Und dann soll die Minderheit konvertieren.



  • Aber es ist doch nicht so, dass der C++-Standard explizit diese Darstellung vorschreibt, oder sehe ich das falsch?

    D.h. ein "double" kann theoretisch(!) anderswo was komplett anderes sein...



  • Der C++-Standard schreibt nichts in der Richtung vor. In der Praxis wird sicher überall ieee-754 verwendet. Aber auch ich bin so paranoid und habe es selbst implementiert. Ich habe in meinen cxxtools einen binaryserializer, wo Fliesskommazahlen tatsächlich auseinandergenommen werden. hier findest Du den Source. Und zwar in der Methode addValueFloat . Im Kern wird die Funktion frexp verwendet. Ich verlasse mich darauf, dass die Standardfunktion möglichst in der Fliesskommaeinheit in Hardware gegossen ist und daher optimal schnell ist.



  • It0101 schrieb:

    Aber es ist doch nicht so, dass der C++-Standard explizit diese Darstellung vorschreibt, oder sehe ich das falsch?

    D.h. ein "double" kann theoretisch(!) anderswo was komplett anderes sein...

    Ja. Und? Was kümmert es dich so lange es praktisch nicht vorkommt?
    Sieh es einfach so...

    Du definierst als Austauschformat einfach "IEEE 754 binary64". Das hat folgende Vorteile:
    * Auf den meisten Maschinen muss nicht konvertiert werden, da sie es direkt verstehen.
    * Es ist ein international anerkannter Standard.
    * Da es ein internationaler Standard ist musst du nichtmal was dokumentieren. Eine Zeile wo steht dass du "IEEE 754 binary64" versendest ist vollkommen ausreichend.
    * Die Chance dass deine Doku falsch verstanden werden kann ist minimal bzw. die Chance dass sich jmd. die nötigen Infos selbst ergoogeln kann ohne dich zu nerven ist sehr gut.

    Wozu willst du also ein anderes, proprietäres Format definieren? Ist doch nur unnötig Aufwand.

    Es gibt in der Softwareentwicklung genug echte Probleme zu lösen. Du musst nicht noch welche dazuerfinden die gar nicht existieren 😉



  • frexp und wie dann weiter?
    Einfach mit 2^63 multiplizieren und nach long long konvertieren?



  • Andererseits, wenn ich dann jedes mal 8 Byte versende, auch wenn die Zahl nicht mal ansatzweise 8 Byte rechtfertigt, ist das auch ganz schöne Platzverschwendung.

    -3,75 braucht z.B. nur 3 Byte, wenn man es brauchbar verpackt. 1 Bit Vorzeichen, 7 Bit Exp, 2 * 7 Bit für die Mantisse ( Basis 10 ) mit Stopbit.

    Andererseits ist natürlich der Aufwand dafür höher, als wenn ich den Double einfach plain auf den Socket drücke.
    Gibts dazu Erhebungen, ob die Ersparnis den Aufwand rechtfertigt? Sowas hat doch bestimmt schonmal irgendein schlauer theoretischer Informatiker untersucht, oder? 😃



  • @tntnet:

    Danke. Gut zu wissen, dass ich nicht der einzige bin, dem bei sowas der Kackstift geht 😃

    PS: ich baue im Prinzip auch nen Serializer...

    Ich hab mir auch schon mal die Frage gestellt, warum ich nicht einfach generell auf Doubles verzichte und einfach alles mit 10^4 multipliziere... Das ist bei meinen Anwendungsfällen ( Wertpapierdaten ) im Prinzip der hauptsächliche Anwendungsfall 😃

    Als Beispiel für effiziente Übertragung von Gleitkommazahlen sind z.b. die Kursdatenströme der Deutschen Börse zu empfehlen. Die senden für einen speziellen Börsenplatz innerhalb 14h 40GB raus. Würden die für jede Gleitkommzahl 8 Byte verwenden, würden den Kunden die Leitungen wegplatzen 😃 Aber das Protokoll, welches die nutzen ist DEUTLICH komplexer und den Aufwand will ich nicht (nochmal) betreiben 😃



  • It0101 schrieb:

    Andererseits, wenn ich dann jedes mal 8 Byte versende, auch wenn die Zahl nicht mal ansatzweise 8 Byte rechtfertigt, ist das auch ganz schöne Platzverschwendung.

    -3,75 braucht z.B. nur 3 Byte, wenn man es brauchbar verpackt. 1 Bit Vorzeichen, 7 Bit Exp, 2 * 7 Bit für die Mantisse ( Basis 10 ) mit Stopbit.

    Warum nicht den ganzen Stream ein wenig packen?



  • Du meinst lzw oder so?

    Hier hab ich mal ein Beispiel gefunden, für das was ich meinte:

    http://stackoverflow.com/questions/4733147/portability-of-binary-serialization-of-double-float-type-in-c

    obwohl nee... der Code ist nicht so meins... irgendwie. Gleitkomma-Multiplikationen... schnell kann das nicht sein.

    Hier noch was:
    http://cpp4theselftaught.com/2013/04/serializing-floats/

    Aber mit logarithmen und pow... wird immer schlimmer. 🙄



  • Entweder du willst Speicher sparen oder Geschwindigkeit optimieren, beides geht selten ...

    Was hast du überhaupt vor? Klingt nach extremem Overengineering.



  • It0101 schrieb:

    Du meinst lzw oder so?

    Ja. LZO oder LZ4 wären meine ersten Gedanken.

    Du definierst als Austauschformat einfach "IEEE 754 binary64".

    Kannst ja gerne bei Programmstart prüfen, ob der Rechner "double"=="IEEE 754 binary64" hat, indem Du sizeof(double)==8 prüfst und ein paar bekannte Werte nach uint64_t oder char[8] reinterpret_castest. Falls der Rechner pöse ist, mußte für ihn was anpassen. Aber es wird nicht passieren.



  • Frage an den TE: Kennst du eine CPU die nicht IEEE 754 verwendet?



  • It0101 schrieb:

    Wertpapierdaten

    Damit meinst du aber keine Geldwerte, oder? Ansonsten stimme ich hustbaer zu. Es gibt keinen Grund im Protokoll nicht einfach zu definieren, dass wert xyz nun mal als "IEEE 754 binary64" gesendet wird. Jeder Rechner der das nativ nicht kann soll dann halt konvertieren, ist ja kein Problem. (Kann man mit LE integern btw. genau so machen.)



  • It0101 schrieb:

    Wertpapierdaten

    Also ich kenn mich mit Wertpapieren jetzt nicht so gut aus, aber ich kann mir nicht vorstellen dass es da viele Daten gäbe die in einer binären Gleitkommazahl gut aufgehoben wären.
    => Nimm was dezimales. Entweder gleich Fixkomma wie du schon selbst geschrieben hast, oder halt ne dezimale Gleitkommazahl.

    Und nicht nur zur Übertragung, du solltest auch nicht im Programm float oder double dafür verwenden. Weil die meisten dezimalen Kommazahlen halt nicht in binären Gleitkommazahlen darstellbar sind.

    ps: zu langsam 🙂


  • Mod

    @volkard: Warum nicht std::numeric_limits<double>::is_iec559 ?

    Was hast du überhaupt vor? Klingt nach extremem Overengineering.

    Programmierer wissen bekanntlich nicht wo es wirklich harkt, performancetechnisch.



  • Naja, er hat nachträglich ja editiert:

    Die senden für einen speziellen Börsenplatz innerhalb 14h 40GB raus.

    Ist doch nichtmal ein MB pro Sekunde. Wenn interessiert da ob beim dekomprimieren "teure" Instruktionen verwendet werden?





  • It0101 schrieb:

    Als Beispiel für effiziente Übertragung von Gleitkommazahlen sind z.b. die Kursdatenströme der Deutschen Börse zu empfehlen. Die senden für einen speziellen Börsenplatz innerhalb 14h 40GB raus

    Ach? Tun wir das bei uns so 😉 ? Ist ja interessant.



  • Ethon schrieb:

    Naja, er hat nachträglich ja editiert:

    Die senden für einen speziellen Börsenplatz innerhalb 14h 40GB raus.

    Ist doch nichtmal ein MB pro Sekunde. Wenn interessiert da ob beim dekomprimieren "teure" Instruktionen verwendet werden?

    Das ist ja nichts an Bandbreite.
    Gehts um Null-Sekunden-Trading? Dann würde ich suchen, wo der "Flaschenhals" ist. "Flaschenhals" im Sinne von Startverzögerung. Oder mich einstellen. 😉


Anmelden zum Antworten