Wie genau ist denn nun float?



  • Daniel E. schrieb:

    aber man kann auch einfach (c=a+b)<a schreiben, wenigstens bei unsigned-Typen.

    Leider nicht:

    unsigned int a = 0X80000000U;
    unsigned int b = 0XFFFFFFFFU;
    unsigned int c = a + b;   /* c: 0X7FFFFFFFU, c < a, (a+b)<a liefert false */
    


  • Power Off schrieb:

    Daniel E. schrieb:

    aber man kann auch einfach (c=a+b)<a schreiben, wenigstens bei unsigned-Typen.

    Leider nicht:

    unsigned int a = 0X8000000U;
    unsigned int b = 0XFFFFFFFU;
    unsigned int c = a + b;   /* c: 0X7FFFFFFFU, c < a, (a+b)<a liefert false */
    

    Hmm, wieso ist c<a?



  • Daniel E. schrieb:

    Hmm, wieso ist c<a?

    Weil 0X7FFFFFFFU eins kleiner ist als 0X80000000U, deshalb. (EDIT: Ach so, Tippfehler, hab ihn schon korrigiert, danke! 🙂 )



  • Portabler waere ohnehin:

    #include <limits.h>
    
    void test( void ) {
       unsigned int a = (unsigned int)( INT_MIN-1 ); /* da INT_MIN = -(2^(n-1)-1) lt. Standard */
       unsigned int b = UINT_MAX;
       unsigned int c = a + b;
       int carry_test = ( a + b ) < a ? 1 : 0;
    }
    

    Achtung: INT_MIN ist im Standard eigentlich falsch definiert, da der kleinste Wert (-32768 bei 16 Bit) nicht repraesentiert wird. Manche Versionen von "limits.h" korrigieren dies, und machen INT_MIN fuer solche Zwecke unbrauchbar.

    Daher ist die folgende Version vielleicht besser:

    #include <limits.h>
    
    void test( void ) {
       unsigned int a = (unsigned int)( 1 << ( CHAR_BIT*sizeof(int)-1 ) );
       unsigned int b = UINT_MAX;
       unsigned int c = a + b;
       int carry_test = ( a + b ) < a ? 1 : 0;
    }
    


  • Power Off schrieb:

    PAchtung: INT_MIN ist im Standard eigentlich falsch definiert, da der kleinste Wert (-32768 bei 16 Bit) nicht repraesentiert wird.

    Haeh? INT_MIN ist die kleinste darstellbare Zahl, nichts anderes. Und im Einerkomplement (dass ausdrücklich erlaubt ist) ist die kleineste Zahl nunmal -32767, im Zweierkomplement -32768.



  • SG1 schrieb:

    Haeh? INT_MIN ist die kleinste darstellbare Zahl, nichts anderes. Und im Einerkomplement (dass ausdrücklich erlaubt ist) ist die kleineste Zahl nunmal -32767, im Zweierkomplement -32768.

    Dann kann man bloss hoffen, dass die Werte in limits.h den Tatsachen entsprechen, und dass die Werte im Standard nicht bloss abgetippt wurden.

    Einerkomplement zur Darstellung negativer Zahlen benutzt naemlich kein mir bekannter Prozessor. (EDIT: Das waere auch Quatsch, weil man dann spezielle Befehle fuer vorzeichenbehaftete Addition und Subtraktion braeuchte, beim Zweierkomplement sind "signed" und "unsigned" dabei egal.)

    (EDIT II: Prinzipiell hast Du aber Recht, siehe Kapitel 6.2.6.2 des Standards: Es sind sogar negative 0-Werte erlaubt! Das macht Ausdruecke wie "(a+b)<a" erst recht non-portabel!)



  • Power Off schrieb:

    Einerkomplement zur Darstellung negativer Zahlen benutzt naemlich kein mir bekannter Prozessor. (EDIT: Das waere auch Quatsch, weil man dann spezielle Befehle fuer vorzeichenbehaftete Addition und Subtraktion braeuchte, beim Zweierkomplement sind "signed" und "unsigned" dabei egal.)

    Dann kennst du vielleicht einfach nicht sehr viele Prozessoren. Wenn es das nicht gäbe, hätte man es nicht berücksichtigen müssen.



  • Power Off schrieb:

    (EDIT II: Prinzipiell hast Du aber Recht, siehe Kapitel 6.2.6.2 des Standards: Es sind sogar negative 0-Werte erlaubt! Das macht Ausdruecke wie "(a+b)<a" erst recht non-portabel!)

    Es ging um unsigned; ich verstehe immer noch nicht, wie man zwei vorzeichenlose Zahlen so addieren kann, das sie (1) überlaufen und (2) trotzdem größer als einer der beiden Summanden werden kann, wenn man Cs Überlaufsemantik übernimmt (ein Restklassenkörper von UINT_MAX+1, sozusagen.)



  • Daniel E. schrieb:

    (2) trotzdem größer als einer der beiden Summanden werden kann,

    Das hat auch keine behauptet. Bei einem Überlauf ist a+b KLEINER als a.



  • SG1 schrieb:

    Daniel E. schrieb:

    (2) trotzdem größer als einer der beiden Summanden werden kann,

    Das hat auch keine behauptet. Bei einem Überlauf ist a+b KLEINER als a.

    Über PowerOffs Geschlecht bin ich nicht informiert, aber das ist genau meine Rede. Ob man ein Carry-Bit abfragt oder (a+b)<a testet ist egal und letzteres ist genormt und damit portabel, was im Widerspruch zu PowerOffs Aussage steht, so wie ich sie verstehe:

    Das macht Ausdruecke wie "(a+b)<a" erst recht non-portabel!



  • In meinem Beispiel ging es darum, dass "(a+b)" eben NICHT "<a" ist in einigen Faellen, trotz Ueberlauf, und dass der Ausdruck damit unbrauchbar ist.

    Ich habe "(a+b)<a" auch frueher gelegentlich benutzt, bis ich gemerkt habe, dass er eigentlich ueberhaupt nicht funktioniert (nicht in allen Faellen!!).

    Dass der Ausdruck "genormt" waere, glaube ich kaum, wenn jemand schon so eine Aussage macht, dann bitte mit Verweis auf die Norm.



  • Power Off schrieb:

    In meinem Beispiel ging es darum, dass "(a+b)" eben NICHT "<a" ist in einigen Faellen, trotz Ueberlauf, und dass der Ausdruck damit unbrauchbar ist.

    Dann her mit *einem* Beispiel, für das das Resultat falsch wird.

    Dass der Ausdruck "genormt" waere, glaube ich kaum, wenn jemand schon so eine Aussage macht, dann bitte mit Verweis auf die Norm.

    Das unsigneds wie angegeben funktionieren (also einen Restklassenring modulo UINT_MAX+1 darstellen), steht in 6.2.5#9 und noch an ein paar anderen Stellen. Man kann jetzt mathematisch zeigen, daß a+b, für a,b aus dem Ring (also unsigned) immer kleiner ist, als a und auch kleiner als b.

    Beispiel für modulo 5:

    + || 0 | 1 | 2 | 3 | 4 |
    ------------------------
    0 || 0 | 1 | 2 | 3 | 4 |
    1 || 1 | 2 | 3 | 4 | 0*|
    2 || 2 | 3 | 4 | 0*| 1*|
    3 || 3 | 4 | 0*| 1*| 2*|
    4 || 4 | 0*| 1*| 2*| 3*|
    

    Die mit dem * markierten Elemente sind "übergelaufen" und ganz offensichtlich ist die "Summe" in diesen Fällen kleiner als die Summanden. Ist bei unsigned haarscharf genau so.



  • angenommen a ist ein usnigned char mit dem wert 255 und b auch, dann ergibt a+b 254 mit überlauf ... aber ... nur wenn das ergebnis selber ein unsigned char ist.
    aber die doofen compiler erweitern ja das ergebnis zu 'nem 'int' so dass a+b 510 ergibt. deshalb haut das (a+b)<a nicht hin. muss noch ein type cast rein.



  • Das Typenkonvertierungen stattfinden ist schon klar, aber dann wird bei a+b für 'unsigned char' wohl kaum ein carry-bit gesetzt und um den Vergleich geht's ja.

    (Außerdem hatte ich am Anfang ja extra (c=a+b)<a vorgeschlagen, wobei das c schreibarbeitssparend im Diskussionsverlauf weggefallen ist.)



  • Sorry, ich glaub' ich hab' 'nen Fehler in meiner Firmware -- mein Beispiel war verkehrt! 🙄 😉 😃


Anmelden zum Antworten