IEEE float umbauen



  • Ich habe das Problem, dass ich eine 32bit-int als float interpretieren möchte, allerdings nicht einfach so - sonst würde ich Euch nicht damit behelligen 😉

    Das normale 32bit IEEE-float ist ja so aufgebaut:

    veeeeeee emmmmmmm mmmmmmmm mmmmmmmm
    

    Bit 31 ist das Vorzeichen, die Bits 23-30 der Exponent und 0-22 die Mantisse. Leider haben meine Zahlen den unumgänglichen Nachteil. dass die Bits 0-7 immer 0 sind, die 32 Bit sehen also so aus:

    veeeeeee emmmmmmm mmmmmmmm 00000000
    

    Da ich sehr große Zahlen sowieso nicht brauche, würde ich gerne den Exponenten zugunsten der Stellen der Mantisse verkürzen, etwa um 3 Bit, so dass die Verteilung dann so wäre:

    veeeeeMM Mmmmmmmm mmmmmmmm 00000000
    

    Damit das Ganze dann immer noch eine legale 32bit-float-Zahl darstellt, müssen die Mantissenbits nach unten rutschen:

    veeeee?? ?MMMmmmm mmmmmmmm mmm00000
    

    Bleibt als Problem der Exponent, der eben nicht einfach als Zahl, sondern als Differenz zu 127 interpretiert wird (laut IEEE).
    Wie muss ich die 5 Bits verrechen, um einen symmetrisch um 0 liegenden (-16 bis +15) 8-Bit-Exponenten zu bekommen?
    Ich mache das momentan so:

    unsigned int vz = arg & 0x80000000;
     unsigned int ex = arg & 0x7c000000;
     unsigned int mt = arg & 0x03ffff00;
     ex >>= 26;
     ex += 112;
     ex <<= 23;
     mt >>= 3;
     arg = vz|ex|mt;
    

    ...fühle mich aber nicht so ganz wohl damit, ich blicke es irgendwie nicht komplett 😞

    Vorschläge oder Korrekturen?



  • Selbstzitat...

    Ich habe es jetzt so gelöst, und fühle mich etwas besser damit:

    union
    {
       unsigned int i;
       struct
       {
          unsigned mt : 23;
          unsigned ex : 8;
          unsigned vz : 1;
       } bits;
    } ieee_flt;
    union
    {
       unsigned int i;
       struct
       {
          unsigned off : 8;
          unsigned mt : 18;
          unsigned ex : 5;
          unsigned vz : 1;
       } bits;
    } my_flt;
    my_flt.i = arg;
    ieee_flt.bits.vz = my_flt.bits.vz;
    ieee_flt.bits.mt = my_flt.bits.mt<<5;
    ieee_flt.bits.ex = 112+my_flt.bits.ex;
    arg = ieee_flt.i;
    

    Klappt auch wie erwartet, nur: was ist bei Bit-structs mit der Endian-ness? Ist dieser Code zwischen Bigendian- und Smallendian-Architekturen portabel?



  • Der code ist überhaupt nichtportabel, da man unions nicht so zum casten nehmen darf. (Wenns nur gcc ist, ist -fno-strict-alias dein freund).



  • Danke schön für die Antwort! Ja, dass das nicht portabel ist, habe ich inzwischen feststellen müssen, gcc ist es auch, aber der hat nicht gewarnt.
    Ich habe das jetzt mit Bitshiften und Ausmaskieren aus einem unsigned int gelöst, da geht es - auch wenn es häßlich aussieht:

    unsigned int vz = arg&0x80000000;
                   unsigned int ex = arg&0x7c000000;
                   ex >>= 26;
                   ex += 111;
                   ex <<= 23;
                   unsigned int mt = arg&0x03ffff00;
                   mt >>= 3;
                   arg = vz|ex|mt;
    

Anmelden zum Antworten