C++ float/double -> mantisse + exponent darstellung



  • Hallo, ich weiß dass z.b. ein Flaot so aufgebaut ist:

    Byte 3 Byte 2 Byte 1 Byte 0
    76543210 76543210 76543210 76543210
    SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM

    S = Vorzeichen
    E = Exponent
    M = Mantisse

    Aber man kann doch in c++ nur bytes ansprechen und nicht direkt die bits oder ?
    Denn so weiß ich im mom nicht wie ich die mantisse extrahieren soll...

    Sinn ist folgender:
    Ich will die Mantisse und den Exponenten in zwei integer Variablen konvertieren...

    Habt ihr ne Idee?

    Gruß Chris



  • du kannst mit bitoperationen und shiften an die einzelnen bits rankommen. Bsp für exponent:

    typedef unsigned int DWORD;
    float val = 1.222f;
    
    DWORD tmp(*(DWORD*)&val);  // temp hat selbe bits. Hier müsste jetzt eigetnlich 
    // ein reinterpret_cast hin, hab ihc aber jetz kein bock zu :)
    
    DWORD exp = tmp & 0x7F800000;
    exp = exp >> 23; // hier müsste jetzt der exponent drin stehen.
    

    Mit mantisse dann analog. Musst aber an die hidden one denken



  • was soll das hier bewirken ?
    DWORD exp = tmp & 0x7F800000;

    Also ich mein die und-verknüpfung mit dem Hex-Wert... ?

    Also diese Idee hatte ich auch schon, aber ich dachte bei der Konvertierung werden die nach komme stellen abgeschnitten oder ist das hier nicht der fall ? da flaot nur anders dargestellt wird ?

    GRuß Chris



  • Achja und wie bekomm ich die Mantisse... ? Ich zwar den long Wert nach >> verschieben aber die mantisse geht ja vom 4 bis zum 2 byte .. also müsste man doch theoretisch den exponeten wieder nach links verschieben und dann den ursprungswert und den exp wert mit ^ verknüpfen odeR ?
    Hat sowas denn noch niemand versucht ?
    Mein Anwedungsgebiet:
    Ich arbeite im mom an einer netzwerk library.. so aber short und longs sollten ja(für mehr plattform unabhängigkeit) in big endian und wieder zurück konvertiert werden.. so nun gibst aber keine Funktion die das direkt mit floats macht ... deshalb... dacht ich mir : packste einfach mantisse und exponent in einen long jeweils..

    Gruß Chris



  • also, ich glaube richtig verstanden hast du das noch nicht:

    float wert = 1.2f;
    DWORD bits=*reinterpret_cast<DWORD*>(&wert);
    // in bits steht das selbe Bitmuster wie in wert.
    // die bitoperationen können nur auf integrale typen angewendet werden, daher muss man 
    // das erst so umwandeln
    
    // bits mit der Maske 0111 1111 1000 0000 0000 0000 0000 0000 maskieren. Es bleiben nur
    // die bits des exponenten übrig
    DWORD exp = bits & 0x7F800000;
    // exp enthält jetzt nur noch die bits die für den exponenten benutzt sind. Diese stehen
    // jedoch an falscher Stelle, deshalb ncoh nach rechts schieben
    exp = exp >> 23;
    
    int exp2 = exp; // in integer mit vorzeichen, offset abziehn:
    exp2 = exp2 - 127;
    cout << "Der Exponent von " << wert << "ist " << exp2 endl;
    
    // mantisse:
    DWORD mant = bits & 0x007FFFFF; // nicht mehr schieben nötig, steht schon ganz rechts
    // Die Bits der Mantisse stehen jetzt in man drin. Direkt ausgeben bring jetzt jedoch nichts, da das ja eigentlich eine festkommazahl ist. könnte man so ausgeben:
    float mant2 = 1.0f + (float)mant/float(0x00800000); // bin mir mit 0x0080000 nich sicher
    cout << "Die Mantisse ist " << mant2 << endl;
    

    Aber für das eigetnliche problem mit der netzwerklib, warum interpretierst du die bits des floats nicht einfach als die bits eines integers? dann kannst du damit umgehen wie mit ints und alles hat sich. Umwandeln wenn nötig, und zurück dann eben so:

    DWORD in_data;
    float alsfloat = *reinterpret_cast<float*>(&in_data);
    

    Gruß, Maxi



  • würde das denn funktioneren ? also ich mein würde das denn richtig nach network-byte-order konvertiert werden ?

    Gruß Chris

    ps:

    beudetet dieses bitmuster folgendes:

    0x007FFFFF = 0000 0000 0111 1111 1111 1111 1111 1111



  • pack doch die zahl in einen string, dann brauchst du dir um order keinen kopp zu machen.
    ansonsten:

    float a;
    long converted = htonl(*reinterpret_cast<long *>(&a));



  • pack doch die zahl in einen string, dann brauchst du dir um order keinen kopp zu machen.
    ansonsten:

    float a;
    long converted = htonl(*reinterpret_cast<long *>(&a));

    Sind denn beide lösungen gut ? bzw... schneller etc.. ich denk mal das die konvertierung in einen string länger dauert als htonl + casten oder ?



  • bei einem massenfloatversand via tcp/ip kannst floats in strukturen bzw. strukturarrays einbetten, da brauchst du nix konvertieren



  • Foxx90 schrieb:

    Sind denn beide lösungen gut ? bzw... schneller etc.. ich denk mal das die konvertierung in einen string länger dauert als htonl + casten oder ?

    am lägsten dürfte das senden über netzt dauern. bis so ein floatstring durch ist, ist er auf der anderen seite sozusagen schon zichfach entpackt


Anmelden zum Antworten