Wie funktioniert diese Bit-Manipulation in Java?

8

Ich habe untersucht, wie Java Bits zählt, die von einem int. gesetzt wurden Ich hatte so etwas Einfaches (was ich für richtig halte):

%Vor% Stattdessen habe ich eine Methode gefunden, von der ich absolut keine Ahnung habe, was vorgeht (scheint mir magisch):

%Vor%

Könnte jemand helfen, zu verstehen, was das tut und warum eine einfache Funktion wie die, die ich als erste gedacht habe, schlecht ist / könnte?

    
Cratylus 03.06.2012, 21:15
quelle

2 Antworten

7

Sicher

%Vor%

Das Bitmuster von 5 ist 0101 (vier Bits), also ist die Maske eine Wiederholung des Bitmusters 01 sechzehnmal. Diese Zeile zählt die Anzahl der Bits in jedem Zwei-Bit-Paar der Anzahl. Wenn Sie Zwei-Bit-Paare in Betracht ziehen, erhält (i >>> 1) & 0x1 das höherwertige Bit in der niederwertigen Position. Jetzt gibt es vier mögliche Zwei-Bit-Muster

%Vor%

und jedes Zwei-Bit-Paar enthält jetzt die Anzahl der Bits, die das Original in diesen Positionen hatte.

%Vor%

Als nächstes zählen wir die Bits, die in jeder Vier-Bit-Gruppe waren (aka Nibble). Indem ein Nibble mit 0x3 = 0011(b) maskiert wird, erhalten wir die Anzahl von Bits, die in den zwei Bits niedrigerer Ordnung des Nibbles waren, und (i >>> 2) & 0x3 erhält den Zählwert von den zwei Bits höherer Ordnung des Nibbles. Diese Zählungen werden jetzt hinzugefügt. Da jede Zählung höchstens 2 betrug, ist die Summe höchstens 4 und verlässt das Nibble nicht.

%Vor%

Jetzt werden die Bits in jedem Oktett gezählt. Jedes Nibble enthält die Anzahl der Bits, die im Original an dieser Stelle gesetzt sind. Die Verschiebung nach rechts um vier Bits verschiebt den Zählwert von dem Nibble höherer Ordnung an jeder Stelle zu dem Nibble niedrigerer Ordnung, diese werden addiert. Dann haben wir auch den Zählwert vom Nibble niedrigerer Ordnung in das Nabel höherer Ordnung des benachbarten Oktetts verschoben, das durch & 0x0f0f0f0f maskiert wird. Da jedes Oktett maximal acht Bits gesetzt haben kann, verlässt die Zählung das Nibble niedriger Ordnung des Oktetts nicht.

%Vor%

Jetzt fügen wir die Anzahl der Paare benachbarter Oktette hinzu.

%Vor%

Nun addieren wir die Summen der Zählungen in den zwei Oktetts höherer Ordnung und den zwei niedriger Ordnung.

%Vor%

Schließlich werden alle Oktette außer dem Oktett der niedrigsten Ordnung maskiert, da die Oktette höherer Ordnung noch Zwischenzahlen enthielten.

Der Grund, warum Ihre einfache Implementierung als schlecht angesehen wird, ist die Leistung. Der gefaltete Bit-Hack verwendet weniger Operationen und keine Verzweigungen, also ist er schneller. Es ist jedoch viel einfacher, falsch zu liegen.

Eine weitere nette Methode, um die gesetzten Bits in int (oder long ) zu zählen, ist

%Vor%

Das funktioniert, weil n = n & (n-1) das zuletzt gesetzte Bit in n löscht und alles andere unberührt lässt. Wenn das Bitmuster von n mit

endet %Vor%

Das Bitmuster von n-1 ist

%Vor%

und die Bits vor dem letzten 1-Bit in n sind gleich. In Java funktioniert das garantiert auch für negative Zahlen, weil der Integer-Überlauf eine Wrap-Around-Semantik hat. Wenn also n = Integer.MIN_VALUE , wird das Bitmuster 100...0 und n - 1 wird Integer.MAX_VALUE mit dem Bitmuster 011...1 .

    
Daniel Fischer 03.06.2012, 22:30
quelle
3

Die coole Methode funktioniert nur, da der Computer einen endlichen Wertebereich für int hat. es wird nicht funktionieren (und so andere coole Bits Algorithmen) so leicht für unendliche Reichweite (wie BigInteger), da Sie alle benötigten Masken vor der Berechnung kennen müssen.

Auf jeden Fall können Sie lesen, wie es funktioniert: Ссылка

es ist am Ende dieses Kapitels.

    
android developer 03.06.2012 22:26
quelle

Tags und Links