w &= 0xfffffffc



  • camper schrieb:

    void TruncateWidth(unsigned& w)
    {
       w -= w % 4;
    }
    

    erzeugt den gleichen Code, wenn der Compiler was taugt. Beachte die Verwendung von unsigned hier, denn bei negativen ints ist das Ergebnis des and (bei 2er Komplement) nicht durch 4 teilbar.

    hm ok stimmt, daran habe ich gar nicht gedacht.
    bin aufgrund der breitenangabe eines bildes von positiven werten ausgegangen.



  • camper schrieb:

    void TruncateWidth(unsigned& w)
    {
       w -= w % 4;
    }
    

    erzeugt den gleichen Code, wenn der Compiler was taugt.

    void TruncateWidth (unsigned& w)
    {
       w = (w>>2)<<2;
    }
    

    erzeugt den gleichen Code, wenn der Compiler was taugt.



  • C++Fan 2009 schrieb:

    camper schrieb:

    void TruncateWidth(unsigned& w)
    {
       w -= w % 4;
    }
    

    erzeugt den gleichen Code, wenn der Compiler was taugt.

    void TruncateWidth (unsigned& w)
    {
       w = (w>>2)<<2;
    }
    

    erzeugt den gleichen Code, wenn der Compiler was taugt.

    Bei unsigned kann man ja wieder ohne Bedenken bzgl Portabilität

    void TruncateWidth (unsigned & w)
    {
       return w & -4;
    }
    

    schreiben.



  • Jetzt, wo ich verstehe was da abläuft, kann ich's ja so lassen.
    Aber vielen Dank an Alle.



  • Sebastian Pizer schrieb:

    Bei unsigned kann man ja wieder ohne Bedenken bzgl Portabilität

    void TruncateWidth (unsigned & w)
    {
       return w & -4;
    }
    

    schreiben.

    bloß das

    void TruncateWidth (unsigned & w)
    

    keinen rückgabewert hat...
    sry für [klugscheiß].



  • Keithy schrieb:

    Sebastian Pizer schrieb:

    Bei unsigned kann man ja wieder ohne Bedenken bzgl Portabilität

    void TruncateWidth (unsigned & w)
    {
       return w & -4;
    }
    

    schreiben.

    bloß das

    void TruncateWidth (unsigned & w)
    

    keinen rückgabewert hat...
    sry für [klugscheiß].

    Richtig. Ich hatte es zwischendurch zu einer Funktion a la
    unsigned TruncateWidth (unsigned w)
    geändert und dann nur zur Hälfte wieder zurück. So muss es natürlich
    w &= -4;
    heißen.

    Gruß,
    SP



  • Sebastian Pizer schrieb:

    Bei unsigned kann man ja wieder ohne Bedenken bzgl Portabilität

    void TruncateWidth (unsigned & w)
    {
       return w & -4;
    }
    

    schreiben.

    wieso? muss -4 auf jedem system dieser erde 0xfffffffc sein?
    🙂



  • Basher schrieb:

    wieso? muss -4 auf jedem system dieser erde 0xfffffffc sein?
    🙂

    Das nicht, aber es wird ja implizit zu einem unsigned konvertiert, bevor & angewendet wird. unsigned(-4) liefert garantiert eine vorzeichenlose Zahl mit Bitmuster "11...1100" -- auch, wenn Du einen Exoten hast, der für vorzeichenbehaftete Ganzzahlen nicht das 2er-Komplement benutzt.



  • Sebastian Pizer schrieb:

    Basher schrieb:

    wieso? muss -4 auf jedem system dieser erde 0xfffffffc sein?
    🙂

    Das nicht, aber es wird ja implizit zu einem unsigned konvertiert, bevor & angewendet wird. unsigned(-4) liefert garantiert eine vorzeichenlose Zahl mit Bitmuster "11...1100".

    wenn nun aber für negative zahlen kein zweier-, sondern z.b. einerkomplement benutzt wird (sowas solls ja geben), dann ist -4 111...1011. damit löschste nur bit 2 weg, nicht bit 1 und 0, wie geplant.
    btw, noch 'ne variante:

    unsigned TruncateWidth (unsigned w)
    {
       return (w/4)*4;
    }
    

    🙂



  • Basher schrieb:

    wenn nun aber für negative zahlen kein zweier-, sondern z.b. einerkomplement benutzt wird (sowas solls ja geben), dann ist -4 111...1011.

    Spielt keine Rolle. Der C++ Standard sagt genau, was passiert, wenn Du eine vorzeichenbehaftete Zahl zu einer vorzeichenlosen Zahl konvertierst. Das Bitmuster, was Du danach erhälst entspricht immer dem 2er-Komplement.



  • Sebastian Pizer schrieb:

    Der C++ Standard sagt genau, was passiert, wenn Du eine vorzeichenbehaftete Zahl zu einer vorzeichenlosen Zahl konvertierst. Das Bitmuster, was Du danach erhälst entspricht immer dem 2er-Komplement.

    biste sicher? was passiert bei:

    // angenommen: negative zahlen sind einerkomplement, 'signed magnitude' oder was anderes
    unsigned a = (unsigned)-4;  // <-- a enthält jetzt bitmuster von -4 im zweierkomplement, nach deiner aussage
    int b = (int)a; // bekommen wir hier unsere -4 zurück? wohl kaum.
    

    🙂



  • Basher schrieb:

    biste sicher?

    Ja. Soll ich jetzt noch die Stelle aus dem Standard raussuchen? Müste irgendwo bei "standard conversions" sein. Das mit dem Bitmuster ergibt sich aus der Regel, dass bei "u=s;" -- wobei u eine vorzeichenlose Integervariable und s irgend eine andere Integervariable (meinetwegen auch long) ist -- folgendes gilt:
    u = s modulo (2 hoch N), N ist hier die Zahl der Bits in u.

    Basher schrieb:

    was passiert bei:

    // angenommen: negative zahlen sind einerkomplement, 'signed magnitude'
    // oder was anderes
    unsigned a = (unsigned)-4;  // <-- a enthält jetzt bitmuster von
                                // -4 im zweierkomplement, nach deiner aussage
    int b = (int)a; // bekommen wir hier unsere -4 zurück? wohl kaum.
    

    Nein. Konvertieren in eine vorzeichenbehaftete Zahl ist "implementation-defined", falls der zugewiesene Wert nicht im Wertebereich liegt. Steht auch so im Standard. Guck mal selbst nach. :p

    Gruß,
    SP



  • msvc++

    ohne probleme kommt da -4 raus. bitmuster bei beiden: 0xfffffffc

    🙂


  • Mod

    Für meinen Geschmack ist das diese Variante (x & -4u) ein bisschen zu subtil, auch wenn ich zugeben muss, dass ich das früher auch so geschrieben habe.
    x & ~(4u-1) ist vielleicht ein bisschen besser. Bei heutigen Compilern gibt es aber eigentlich nur noch selten einen Grund, das im Code stehen zu lassen.
    Sowas hab ich in der Wildnis auch schon gesehen:

    int foo;
    while ( foo % 4 != 0 )
        foo--;
    

    Da ziehe ich dann sogar ein einfaches & vor 😉



  • Sebastian Pizer schrieb:

    Das mit dem Bitmuster ergibt sich aus der Regel, dass bei "u=s;" -- wobei u eine vorzeichenlose Integervariable und s irgend eine andere Integervariable (meinetwegen auch long) ist -- folgendes gilt:
    u = s modulo (2 hoch N), N ist hier die Zahl der Bits in u.

    das glaube ich dir, aber das daraus in jedem fall ein zweierkomplement wird, egal mit welcher kodierung ein system negative zahlen speichert, kann ich mir nicht vorstellen.

    helferlein schrieb:

    msvc++
    ohne probleme kommt da -4 raus. bitmuster bei beiden: 0xfffffffc

    wir reden hier von 'nicht-zweierkomplement' systemen.

    camper schrieb:

    Für meinen Geschmack ist das diese Variante (x & -4u) ein bisschen zu subtil...

    finde ich auch.
    🙂



  • da wir jetzt alle 1000 tricks kennen, die unteren zwei bits zu löschen, mal andersrum: wie kommt man am schnellsten auf das nächste grössere vielfache von 4? bitte, postet eure vorschläge....
    🙂



  • Basher schrieb:

    Sebastian Pizer schrieb:

    Das mit dem Bitmuster ergibt sich aus der Regel, dass bei "u=s;" -- wobei u eine vorzeichenlose Integervariable und s irgend eine andere Integervariable (meinetwegen auch long) ist -- folgendes gilt:
    u = s modulo (2 hoch N), N ist hier die Zahl der Bits in u.

    das glaube ich dir, aber das daraus in jedem fall ein zweierkomplement wird, egal mit welcher kodierung ein system negative zahlen speichert, kann ich mir nicht vorstellen.

    Das folgt direkt aus der Modulo-Regel.

    //   2er-K           1er-K           Sign+Mag
    int      s = -10;  //   111...11110110  111...11110101  100...00001010
    
                       //  1000...00000000  (2^N)
                       // - 000...00001010  (10)
                       //  ---------------
    unsigned u = s;    //   111...11110110  (2^N - 10 = -10 mod 2^N)
    

    Gruß,
    SP



  • Basher schrieb:

    da wir jetzt alle 1000 tricks kennen, die unteren zwei bits zu löschen, mal andersrum: wie kommt man am schnellsten auf das nächste grössere vielfache von 4? bitte, postet eure vorschläge....

    Ich nehme an, dass falls die Zahl schon durch 4 teilbar ist, dass sie dann nicht verändert werden soll.

    inline unsigned aufrunden(unsigned x)
    {
      return (x+3) & unsigned(-4);
    }
    

    Gruß,
    SP



  • Sebastian Pizer schrieb:

    //   2er-K           1er-K           Sign+Mag
    int      s = -10;  //   111...11110110  111...11110101  100...00001010
    
                       //  1000...00000000  (2^N)
                       // - 000...00001010  (10)
                       //  ---------------
    unsigned u = s;    //   111...11110110  (2^N - 10 = -10 mod 2^N)
    

    ok, das sieht überzeugend aus (obwohl nicht das 'mod', also % benutzt wird, was wir in C so haben).

    Sebastian Pizer schrieb:

    Basher schrieb:

    da wir jetzt alle 1000 tricks kennen, die unteren zwei bits zu löschen, mal andersrum: wie kommt man am schnellsten auf das nächste grössere vielfache von 4? bitte, postet eure vorschläge....

    Ich nehme an, dass falls die Zahl schon durch 4 teilbar ist, dass sie dann nicht verändert werden soll.

    ja, und 0 soll auch 0 bleiben. noch mehr vorschläge?
    🙂



  • Es ist alles Wichtige gesagt. Den Rest mußt du dir denken.


Anmelden zum Antworten