Ungerader Bitoperator in der Inkrementanweisung einer for-Schleife [duplicate]

Lesezeit: 5 Minuten

Benutzer-Avatar
Benutzer4213270

Angesichts dieser For-Schleife:

for(++i; i < MAX_N; i += i & -i)

was soll es bedeuten? Was bedeutet die Aussage i += i & -i erreichen?

  • @ user3670482 Dies ist ein einfacher Schnappschuss eines Codes, alle Variablen sind im gesamten Code gut definiert

    – Benutzer4213270

    4. November 2014 um 7:54 Uhr

  • Was ist der Anfangswert von i? Ich frage mich, warum der Programmierer das nicht einfach verwendet i <<= 1.

    – Salmann A

    4. November 2014 um 10:30 Uhr

  • @SalmanA Weil i <<= 1 ist nicht das, was der Programmierer will?

    – Gyapti Jain

    4. November 2014 um 12:50 Uhr

  • Was ist der Anfangswert von i?

    – Jan Hudec

    4. November 2014 um 13:56 Uhr

  • ähnlich: stackoverflow.com/questions/24772669/…

    – phuklv

    5. Dezember 2014 um 10:15 Uhr

Benutzer-Avatar
Gyapti Jain

Diese Schleife wird häufig bei der Implementierung eines binär indizierten Baums (oder BIT) beobachtet, die nützlich ist, um einen Bereich oder einen Punkt zu aktualisieren und einen Bereich oder einen Punkt in logarithmischer Zeit abzufragen. Diese Schleife hilft bei der Auswahl des geeigneten Buckets basierend auf dem gesetzten Bit im Index. Für weitere Details lesen Sie bitte etwas über BIT aus einer anderen Quelle. Im folgenden Beitrag werde ich zeigen, wie diese Schleife hilft, die geeigneten Buckets basierend auf den niederwertigsten gesetzten Bits zu finden.

2s komplementäres vorzeichenbehaftetes System (wenn i vorzeichenbehaftet ist)
i & -i ist ein Bit-Hack, um schnell die Zahl zu finden, die zu einer gegebenen Zahl hinzugefügt werden sollte, um das nachfolgende Bit zu 0 zu machen (deshalb ist die Leistung von BIT logarithmisch). Wenn Sie eine Zahl in negieren 2s Komplementärsystemerhalten Sie eine Zahl mit Bits in umgekehrtem Muster hinzugefügt 1 dazu. Wenn Sie hinzufügen 1würden alle niederwertigen Bits beginnen zu invertieren, solange sie es sind 1 (war 0 in Originalnummer). Zuerst 0 bisschen angetroffen (1 im Original i) würde werden 1.

Wenn Sie und beide i und -inur dieses Bit (am wenigsten signifikant 1 Bit) würde gesetzt bleiben und alle niederwertigen (rechten) Bits würden gesetzt bleiben zero und signifikantere Bits wären inverse der Originalnummer.

Anding würde eine Leistung von erzeugen 2 Nummer, die, wenn sie zur Nummer hinzugefügt wird i würde das niedrigstwertige gesetzte Bit löschen. (gemäß der Anforderung von BISSCHEN)

Zum Beispiel:

i = 28
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
+---+---+---+---+---+---+---+---+
                      *
-i
+---+---+---+---+---+---+---+---+
| 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 |
+---+---+---+---+---+---+---+---+
  I   I   I   I   I   S   Z   Z
Z = Zero
I = Inverted
S = Same
* = least significant set bit

i & -i
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+---+---+---+---+---+---+---+---+

Adding
+---+---+---+---+---+---+---+---+
| 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
+---+---+---+---+---+---+---+---+
                      x
x = cleared now

Unsigned (wenn i unsigned ist)

Es funktioniert sogar für 1s complementary system oder irgendein anderes Repräsentationssystem solange i ist unsigned aus folgendem Grund:

-i wird Wert nehmen 2sizeof(unsigned int) * CHAR_BITS – ich. Somit würden alle Bits bis zum niederwertigsten gesetzten Bit verbleiben zerodas niedrigstwertige Bit würde ebenfalls Null bleiben, aber alle Bits danach würden wegen der Übertragsbits invertiert.

Zum Beispiel:

i = 28
     +---+---+---+---+---+---+---+---+
     | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
     +---+---+---+---+---+---+---+---+
                           *
-i
   0   1   1   1   1   1   <--- Carry bits
     +---+---+---+---+---+---+---+---+
   1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
     +---+---+---+---+---+---+---+---+
     +---+---+---+---+---+---+---+---+
   - | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
     +---+---+---+---+---+---+---+---+
   ----------------------------------------
     +---+---+---+---+---+---+---+---+
     | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 |
     +---+---+---+---+---+---+---+---+
       I   I   I   I   I   S   Z   Z
Z = Zero
I = Inverted
S = Same
* = least significant set bit

i & -i
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+---+---+---+---+---+---+---+---+

Adding
+---+---+---+---+---+---+---+---+
| 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
+---+---+---+---+---+---+---+---+
                      x
x = cleared now

Implementierung ohne Bithack

Sie können auch verwenden i += (int)(1U << __builtin_ctz((unsigned)i)) auf gcc.

Live-Beispiel hier

Eine nicht verschleierte Version für dasselbe wäre:

/* Finds smallest power of 2 that can reset the least significant set bit on adding */
int convert(int i) /* I purposely kept i signed as this works for both */
{
    int t = 1, d;
    for(; /* ever */ ;) {
        d = t + i; /* Try this value of t */
        if(d & t) t *= 2;  /* bit at mask t was 0, try next */
        else break; /* Found */
    }
    return t;
}

BEARBEITEN
Hinzufügen von dieser Antwort:

Unter der Annahme des Zweierkomplements (oder dass i vorzeichenlos ist), ist -i gleich ~i + 1.

i & (~i + 1) ist ein Trick, um das niedrigste gesetzte Bit von i zu extrahieren.

Es funktioniert, weil +1 tatsächlich das niedrigste Löschbit setzt und alle darunter liegenden Bits löscht. Das einzige Bit, das sowohl in i als auch in ~i+1 gesetzt ist, ist das niedrigste gesetzte Bit von i (d. h. das niedrigste Löschbit in ~i). Die darunter liegenden Bits sind in ~i+1 gelöscht, und die darüber liegenden Bits sind zwischen i und ~i ungleich.

  • 2s complementary system Es sollte darauf hingewiesen werden, dass C++ kein Zweierkomplement vorschreibt, sodass es auf verschiedenen Plattformen durchaus unterschiedliche Auswirkungen haben kann. So oder so sollte dieser Code zurück in die 80er Jahre verbannt werden, aus denen er stammt.

    – Benutzer657267

    4. November 2014 um 7:57 Uhr

  • Viele Bithacks sind abhängig von der Darstellung (2s, IEEE Floating Point etc.) Man sollte diese auf eigene Faust verwenden. Auf 1s-System können Sie so etwas wie verwenden if(i) (i & (-i) + 1)

    – Mohit Jain

    4. November 2014 um 8:02 Uhr

  • Bedeutet dies, dass das Programm i = 1, 2, 4, 8, 16 … durchläuft?

    – Salmann A

    4. November 2014 um 10:14 Uhr

  • @SalmanA Ja, wenn ich anfangs 0 war. Nein, wenn nicht. Wenn ich zum Beispiel 36 war, wird es als Schleife angezeigt 37 -> 38 -> 40 -> 48 -> 64 -> 128 -> 256 -> 512 ...

    – Gyapti Jain

    4. November 2014 um 10:26 Uhr

  • @harold Wenn man sich die Verwendung dieses Codes ansieht, scheint er in BIT verwendet zu werden. Die Abfrage nach Index 0 testet, ob von 1 : for(++i; i < MAX_N; i += i & -i). So __builtin_ctz ist sicher. Für jede andere Verwendung würde ich es vorziehen, explizit auf Null zu prüfen.

    – Gyapti Jain

    4. November 2014 um 12:29 Uhr


1370570cookie-checkUngerader Bitoperator in der Inkrementanweisung einer for-Schleife [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy