Gleitkommazahlen



  • Hi,

    ich habe eine Verständnisfrage zu Gleitkommazahlen in C++, im besonderen wie die binär kodiert sind. Mein Compiler ist der gcc-4.3 / gcc-4.4 und ich benutze folgendes Testprogramm:

    #include <iostream>
    #include <iomanip>
    #include <sstream>
    
    using namespace std;
    
    template< class T > string get_bin( T a )
    {
        stringstream s;
        unsigned char *aa = (unsigned char*)(&a);
        for( size_t i=0 ; i<sizeof(T) ; ++i )
    	for( int j=7 ; j>=0 ; j--)
                s << ((aa[i] >> j) & 1);
        return s.str();
    }
    
    int main( int argc , char **argv )
    {
        cout << get_bin( 1.0 ) << endl;
        cout << get_bin( -1.0 ) << endl;
        cout << get_bin( 2.0 ) << endl;
        cout << get_bin( 3.0 ) << endl;
        cout << get_bin( 4.0 ) << endl;
    
        return 0;
    }
    

    Die Ausgabe davon ist:

    0000000000000000000000000000000000000000000000001111000000111111
    0000000000000000000000000000000000000000000000001111000010111111
    0000000000000000000000000000000000000000000000000000000001000000
    0000000000000000000000000000000000000000000000000000100001000000
    0000000000000000000000000000000000000000000000000001000001000000
    

    Damit bekommt man schon ein bisschen was raus, z.b. dass das 8.bit von rechts das Vorzeichen markiert. Ich bin mir auch ziemlich sicher, dass die letzten 7 bits den exponenten darstellen. Allerdings habe ich keine Ahnung wie die Mantisse hier kodiert, bzw. dargestellt ist. Kann mir da jemand weiterhelfen oder kennt einige gute Links in denen das erklärt wird?

    Vielen Dank und viele Grüße,

    headmyshoulder


  • Mod

    Wie das genau funktioniert ist zwar nicht durch den Sprachstandard vorgeschrieben, aber fast alle Maschinen benutzen dies hier:
    http://de.wikipedia.org/wiki/IEEE_754



  • Hier ist auch noch etwas über die Darstellung von Fließkommazahlen:

    http://www.cirsovius.de/CPM/Projekte/Artikel/Mathe/IEEE_Reals/IEEE1.html

    MfG, Jochen



  • Es würde die Anschaulichkeit erhöhen wenn du die Endianess beachtest.



  • Tim schrieb:

    Es würde die Anschaulichkeit erhöhen wenn du die Endianess beachtest.

    Jepp, das bringt mich auch schon sehr viel weiter, hier mal der neue Code

    #include <iostream>
    #include <iomanip>
    #include <sstream>
    
    using namespace std;
    
    template< class T >
    inline string get_bin( T a )
    {
        stringstream s;
        unsigned char *aa = reinterpret_cast< unsigned char* >(&a);
        for( int i = sizeof(T)-1 ; i>=0 ; --i )
        {
            for( int j=7 ; j>=0 ; --j)
                s << ((aa[i] >> j) & 1);
            s << " ";
        }
        return s.str();
    }
    
    int main( int argc , char **argv )
    {
        cout << get_bin( 1.0 ) << endl;
        cout << get_bin( -1.0 ) << endl;
        cout << get_bin( 2.0 ) << endl;
        cout << get_bin( 3.0 ) << endl;
        cout << get_bin( 4.0 ) << endl;
    
        return 0;
    }
    

    und die Ausgabe dazu:

    00111111 11110000 00000000 00000000 00000000 00000000 00000000 00000000
    10111111 11110000 00000000 00000000 00000000 00000000 00000000 00000000
    01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
    01000000 00001000 00000000 00000000 00000000 00000000 00000000 00000000
    01000000 00010000 00000000 00000000 00000000 00000000 00000000 00000000
    


  • Vielleicht noch ein paar allgemeine Bemerkungen zu deinem Code:

    int n = sizeof(T);
        if( !n ) return "";
    

    1. Ich würde Vergleiche auf Null explizit hinschreiben ( n == 0 ). Schliesslich ist die Bedeutung eine ziemlich andere als die Negation eines logischen Ausdrucks.
    2. Konstante Ausdrücke (zur Compilezeit bekannt) würde ich mit const deklarieren, das erlaubt dem Compiler Optimierungen und schränkt die Variable nicht unnötig ein.
    3. Der sizeof -Operator gibt niemals 0 zurück, da solch ein Objekt keinen Speicherplatz benötigen würde. Die Abfrage ist also überflüssig.

    unsigned char *aa = (unsigned char*)(&a);
    

    Ich persönlich würde so einen Cast mit reinterpret_cast kenntlich machen.

    for( int i = n-1 ; i>=0 ; --i )
        {
            for( int j=7 ; j>=0 ; j--)
    

    Warum --i , aber j-- ? Hier sind beide Ausdrücke äquivalent, also würde ich mich für einen entscheiden.



  • Nexus schrieb:

    Vielleicht noch ein paar allgemeine Bemerkungen zu deinem Code:

    Danke für die Hinweise, ich geb Dir vollkommen recht. Der Code wurde nur zur Demonstration geschrieben, deswegen vielleicht die eine oder andere Nachlässigkeit.


Anmelden zum Antworten