wake-up-neo.com

Bitweiser Betrieb und Verwendung

Betrachten Sie diesen Code:

x = 1        # 0001
x << 2       # Shift left 2 bits: 0100
# Result: 4

x | 2        # Bitwise OR: 0011
# Result: 3

x & 1        # Bitwise AND: 0001
# Result: 1

Ich kann die arithmetischen Operatoren in Python (und anderen Sprachen) verstehen, aber ich habe bitweise Operatoren nie richtig verstanden. Im obigen Beispiel (aus einem Python-Buch) verstehe ich die Linksverschiebung, nicht aber die beiden anderen.

Wofür werden eigentlich bitweise Operatoren verwendet? Ich würde einige Beispiele schätzen.

85
3zzy

Bitweise Operatoren sind Operatoren, die mit Multi-Bit-Werten arbeiten, jedoch konzeptweise jeweils ein Bit.

  • AND ist nur 1, wenn beide ihrer Eingänge 1 sind, andernfalls 0.
  • OR ist 1, wenn einer oder beide seiner Eingänge 1 sind, andernfalls 0.
  • XOR ist nur 1, wenn genau einer ihrer Eingänge 1 ist, andernfalls 0.
  • NOT ist nur 1, wenn ihre Eingabe 0 ist, andernfalls 0.

Diese können am besten als Wahrheitstabellen dargestellt werden. Die Eingabemöglichkeiten befinden sich oben und links. Das resultierende Bit ist einer der vier Werte (zwei im Fall von NOT, da nur ein Eingang vorhanden ist), die am Schnittpunkt der Eingänge angezeigt werden.

AND | 0 1     OR | 0 1     XOR | 0 1    NOT | 0 1
----+-----    ---+----     ----+----    ----+----
 0  | 0 0      0 | 0 1       0 | 0 1        | 1 0
 1  | 0 1      1 | 1 1       1 | 1 0

Ein Beispiel ist, wenn Sie nur die unteren 4 Bits einer Ganzzahl benötigen, UND Sie mit 15 (binär 1111) UND:

    201: 1100 1001
AND  15: 0000 1111
------------------
 IS   9  0000 1001

Die Null-Bits in 15 wirken in diesem Fall effektiv als Filter, wodurch die Bits im Ergebnis ebenfalls Null werden.

Außerdem sind >> und << oft als bitweise Operatoren enthalten, die um einen bestimmten Wert nach rechts bzw. links um eine bestimmte Anzahl von Bits "verschoben" werden. Dabei werden Bits weggeworfen, die an dem Ende, zu dem Sie wechseln, rollen und Null-Bits eingespeist werden am anderen Ende.

Also zum Beispiel:

1001 0101 >> 2 gives 0010 0101
1111 1111 << 4 gives 1111 0000

Beachten Sie, dass die Verschiebung nach links in Python ungewöhnlich ist, da keine feste Breite verwendet wird, in der Bits verworfen werden. Während viele Sprachen eine feste Breite verwenden, die auf dem Datentyp basiert, erweitert Python einfach die Breite, um zusätzliche Bits bereitzustellen. Um das Verwerfungsverhalten in Python zu erhalten, können Sie einer Verschiebung nach links mit einer bitweisen and folgen, wie in einem 8-Bit-Wert, der vier Bits nach links verlagert:

bits8 = (bits8 << 4) & 255

Ein anderes Beispiel für bitweise Operatoren ist, wenn Sie zwei 4-Bit-Werte haben, die Sie in einen 8-Bit-Wert packen möchten. Sie können alle drei Operatoren verwenden (left-shift, and und or):

packed_val = ((val1 & 15) << 4) | (val2 & 15)
  • Die & 15-Operation stellt sicher, dass beide Werte nur die unteren 4 Bits haben.
  • Der << 4 ist eine 4-Bit-Verschiebung nach links, um val1 in die oberen 4 Bits eines 8-Bit-Werts zu verschieben.
  • Der | kombiniert diese beiden einfach.

Wenn val1 7 ist und val2 4 ist:

                val1            val2
                ====            ====
 & 15 (and)   xxxx-0111       xxxx-0100  & 15
 << 4 (left)  0111-0000           |
                  |               |
                  +-------+-------+
                          |
| (or)                0111-0100
142
paxdiablo

Eine typische Verwendung:

| wird verwendet, um ein bestimmtes Bit auf 1 zu setzen

& wird verwendet, um ein bestimmtes Bit zu testen oder zu löschen

  • Setze ein Bit (wobei n die Bitnummer und 0 das niedrigstwertige Bit ist):

    unsigned char a |= (1 << n);

  • Klar ein bisschen:

    unsigned char b &= ~(1 << n);

  • Ein bisschen umschalten:

    unsigned char c ^= (1 << n);

  • Teste ein bisschen:

    unsigned char e = d & (1 << n);

Nehmen Sie den Fall Ihrer Liste zum Beispiel:

x | 2 wird verwendet, um das Bit 1 von x auf 1 zu setzen

x & 1 wird verwendet, um zu testen, ob Bit 0 von x 1 oder 0 ist

41
pierrotlefou

wofür werden eigentlich bitweise Operatoren verwendet? Ich würde einige Beispiele schätzen.

Bit-Operationen werden am häufigsten für die Analyse von Hexadezimalfarben verwendet.

Zum Beispiel ist hier eine Python - Funktion, die einen String wie #FF09BE akzeptiert und einen Tuple seiner Rot-, Grün- und Blau-Werte zurückgibt.

def hexToRgb(value):
    # Convert string to hexadecimal number (base 16)
    num = (int(value.lstrip("#"), 16))

    # Shift 16 bits to the right, and then binary AND to obtain 8 bits representing red
    r = ((num >> 16) & 0xFF)

    # Shift 8 bits to the right, and then binary AND to obtain 8 bits representing green
    g = ((num >> 8) & 0xFF)

    # Simply binary AND to obtain 8 bits representing blue
    b = (num & 0xFF)
    return (r, g, b)

Ich weiß, dass es effizientere Möglichkeiten gibt, dies zu erreichen, aber ich glaube, dass dies ein wirklich kurzes Beispiel ist, das sowohl Verschiebungen als auch bitweise boolesche Operationen veranschaulicht.

34
bguiz

Ich denke, dass der zweite Teil der Frage: 

Wofür werden eigentlich bitweise Operatoren verwendet? Ich würde einige Beispiele schätzen.

Wurde nur teilweise angesprochen. Das sind meine zwei Cents in dieser Sache. 

Bitweise Operationen in Programmiersprachen spielen beim Umgang mit vielen Anwendungen eine grundlegende Rolle. Fast alle Low-Level-Computing müssen mit dieser Art von Operationen durchgeführt werden. 

In allen Anwendungen, die Daten zwischen zwei Knoten senden müssen, z.

  • computernetzwerke;

  • telekommunikationsanwendungen (Mobiltelefone, Satellitenkommunikation usw.).

In der Kommunikationsebene der unteren Ebene werden die Daten normalerweise in so genannten frames gesendet. Frames sind nur Bytes, die über einen physischen Kanal gesendet werden. Diese Frames enthalten normalerweise die eigentlichen Daten sowie einige andere Felder (in Bytes codiert), die Teil des sogenannten header sind. Der Header enthält normalerweise Bytes, die einige Informationen kodieren, die sich auf den Status der Kommunikation beziehen (z. B. mit Flags (Bits)), Rahmenzähler, Korrektur- und Fehlererkennungscodes usw., um die übertragenen Daten in einem Rahmen zu erhalten und die zu erstellen Frames zum Senden von Daten benötigen Sie sicher bitweise Operationen.

Im Allgemeinen ist beim Umgang mit dieser Art von Anwendungen eine API verfügbar, sodass Sie sich nicht mit all diesen Details befassen müssen. Zum Beispiel bieten alle modernen Programmiersprachen Bibliotheken für Socket-Verbindungen, sodass Sie die TCP/IP-Kommunikationsrahmen nicht wirklich erstellen müssen. Aber denken Sie an die guten Leute, die diese APIs für Sie programmiert haben, sie mussten sich sicher mit der Rahmenkonstruktion befassen. Verwenden aller Arten von bitweisen Operationen, um von der untersten Ebene zur übergeordneten Kommunikation zu wechseln.

Als konkretes Beispiel stellen Sie sich vor, dass Ihnen jemand eine Datei gibt, die Rohdaten enthält, die direkt von Telekommunikationshardware erfasst wurden. In diesem Fall müssen Sie, um die Frames zu finden, die rohen Bytes in der Datei lesen und versuchen, eine Art Synchronisationswort zu finden, indem Sie die Daten bitweise abfragen. Nachdem Sie die Synchronisationswörter identifiziert haben, müssen Sie die tatsächlichen Frames abrufen und ggf. SHIFT (und das ist nur der Anfang der Story), um die tatsächlich übertragenen Daten zu erhalten.

Eine andere sehr untergeordnete Familie von Anwendungen ist die, wenn Sie Hardware mit (alten) Anschlüssen wie parallelen und seriellen Anschlüssen steuern müssen. Diese Ports werden durch das Setzen einiger Bytes gesteuert, und jedes Bit dieser Bytes hat in Anweisungen eine bestimmte Bedeutung für diesen Port (siehe beispielsweise http://en.wikipedia.org/wiki/Parallel_port ). . Wenn Sie Software entwickeln möchten, die mit dieser Hardware etwas tut, benötigen Sie bitweise Operationen, um die Anweisungen, die Sie ausführen möchten, in die Bytes umzuwandeln, die der Port versteht.

Wenn Sie zum Beispiel einige physische Tasten zur Steuerung eines anderen Geräts an den parallelen Anschluss angeschlossen haben, handelt es sich hierbei um eine Codezeile, die Sie in der Softwareanwendung finden können: 

read = ((read ^ 0x80) >> 4) & 0x0f; 

Hoffe das trägt dazu bei.

9
eguaio

Ich hoffe, das klärt diese beiden:

x | 2

0001 //x
0010 //2

0011 //result = 3

x & 1

0001 //x
0001 //1

0001 //result = 1
6
Amarghosh

Stellen Sie sich 0 als falsch und 1 als wahr vor. Dann arbeiten bitweise und (&) und oder (|) genauso wie normal und und oder, außer sie machen alle Bits im Wert auf einmal. Normalerweise werden sie für Flags verwendet, wenn 30 Optionen festgelegt werden können (z. B. als Zeichenstile in einem Fenster). Sie müssen nicht 30 separate boolesche Werte übergeben, um die einzelnen Werte zu setzen oder deren Einstellung aufzuheben um die Optionen zu einem einzigen Wert zusammenzufassen, und mit & prüfen, ob jede Option gesetzt ist. Diese Art der Flag-Weitergabe wird von OpenGL stark verwendet. Da jedes Bit ein separates Flag ist, erhalten Sie Flag-Werte bei Zweierpotenzen (aka Zahlen, für die nur ein Bit festgelegt ist) 1 (2 ^ 0) 2 (2 ^ 1) 4 (2 ^ 2) 8 (2 ^ 3) Die Potenz von Zwei zeigt an, welches Bit gesetzt ist, wenn das Flag gesetzt ist.

Anmerkung 2 = 10, also ist x | 2 110 (6) und nicht 111 (7), wenn sich keines der Bits überlappt (was in diesem Fall wahr ist) | wirkt wie ein Zusatz.

5
stonemetal

Ich habe es oben nicht erwähnt, aber Sie werden auch feststellen, dass einige Leute die Links- und Rechtsverschiebung für Rechenoperationen verwenden. Eine Verschiebung nach links um x entspricht einer Multiplikation mit 2 ^ x (solange sie nicht überläuft) und eine Verschiebung nach rechts entspricht einer Division durch 2 ^ x.

Ich habe kürzlich gesehen, dass Leute x << 1 und x >> 1 zum Verdoppeln und Halbieren verwendet haben, obwohl ich nicht sicher bin, ob sie nur klug zu sein versuchen oder ob es einen deutlichen Vorteil gegenüber den normalen Operatoren gibt.

5
P. Stallworth

Dieses Beispiel zeigt die Operationen für alle vier 2-Bit-Werte:

10 | 12

1010 #decimal 10
1100 #decimal 12

1110 #result = 14

10 & 12

1010 #decimal 10
1100 #decimal 12

1000 #result = 8

Hier ist ein Beispiel für die Verwendung:

x = raw_input('Enter a number:')
print 'x is %s.' % ('even', 'odd')[x&1]
3
dansalmo

Ein weiterer häufiger Anwendungsfall ist das Bearbeiten/Testen von Dateiberechtigungen. Siehe das Python stat-Modul: http://docs.python.org/library/stat.html .

Um beispielsweise die Berechtigungen einer Datei mit einem gewünschten Berechtigungssatz zu vergleichen, können Sie beispielsweise Folgendes tun:

import os
import stat

#Get the actual mode of a file
mode = os.stat('file.txt').st_mode

#File should be a regular file, readable and writable by its owner
#Each permission value has a single 'on' bit.  Use bitwise or to combine 
#them.
desired_mode = stat.S_IFREG|stat.S_IRUSR|stat.S_IWUSR

#check for exact match:
mode == desired_mode
#check for at least one bit matching:
bool(mode & desired_mode)
#check for at least one bit 'on' in one, and not in the other:
bool(mode ^ desired_mode)
#check that all bits from desired_mode are set in mode, but I don't care about 
# other bits.
not bool((mode^desired_mode)&desired_mode)

Ich verwende die Ergebnisse als boolesche Werte, weil mir nur die Wahrheit oder Falschheit wichtig ist, aber es wäre eine lohnende Übung, die bin () -Werte für jeden auszugeben.

2
dbn

Bitrepräsentationen von Ganzzahlen werden häufig beim wissenschaftlichen Berechnen verwendet, um Arrays von wahr/falsch-Informationen darzustellen, da eine bitweise Operation viel schneller ist als das Durchlaufen eines Arrays von Booleschen. (In höheren Sprachversionen wird möglicherweise die Idee eines Bit-Arrays verwendet.)

Ein schönes und recht einfaches Beispiel dafür ist die generelle Lösung des Spiels Nim. Schauen Sie sich den Python code auf der Wikipedia-Seite an. Es wird häufig bitweises Exklusiv oder ^ verwendet.

2
Jonah

ich habe es nicht erwähnt. Dieses Beispiel zeigt die (-) - Dezimaloperation für 2-Bit-Werte: A-B (nur wenn A B enthält)

diese Operation wird benötigt, wenn wir in unserem Programm ein Verb halten, das Bits darstellt. Manchmal müssen wir Bits hinzufügen (wie oben) und manchmal müssen wir Bits entfernen (wenn das Verb dann enthält)

111 #decimal 7
-
100 #decimal 4
--------------
011 #decimal 3

mit Python: 7 & ~ 4 = 3 (Entfernen Sie aus 7 die Bits, die 4 darstellen)

001 #decimal 1
-
100 #decimal 4
--------------
001 #decimal 1

mit Python: 1 & ~ 4 = 1 (Entfernen Sie aus 1 die Bits, die 4 darstellen - in diesem Fall ist 1 nicht "enthält" 4).

1
Eyal Ch

Es gibt möglicherweise eine bessere Methode, um herauszufinden, wo sich ein Array-Element zwischen zwei Werten befindet. Wie dieses Beispiel zeigt, funktioniert & hier, wohingegen und nicht.

import numpy as np
a=np.array([1.2, 2.3, 3.4])
np.where((a>2) and (a<3))      
#Result: Value Error
np.where((a>2) & (a<3))
#Result: (array([1]),)
1
woodfoot

Sets

Sätze können mit mathematischen Operationen kombiniert werden.

  • Der Union-Operator | kombiniert zwei Sätze zu einem neuen, der Elemente enthält. 
  • Der Kreuzungsoperator & erhält Elemente nur in beiden. 
  • Der Differenzoperator - erhält Elemente im ersten Satz, aber nicht im zweiten. 
  • Der symmetrische Differenzoperator ^ ruft Elemente in beiden Gruppen ab, jedoch nicht in beiden.

Versuch es selber:

first = {1, 2, 3, 4, 5, 6}
second = {4, 5, 6, 7, 8, 9}

print(first | second)

print(first & second)

print(first - second)

print(second - first)

print(first ^ second)

Ergebnis:

{1, 2, 3, 4, 5, 6, 7, 8, 9}

{4, 5, 6}

{1, 2, 3}

{8, 9, 7}

{1, 2, 3, 7, 8, 9}
1
PUNEET JAIN

die folgenden bitweisen Operatoren: & , | , ^ und ~ geben Werte (basierend auf ihrer Eingabe) auf dieselbe Weise zurück, dass Logikgatter / Signale beeinflussen. Sie könnten sie zum Emulieren von Schaltungen verwenden.

0
Erik Waters

Zum Umdrehen von Bits (d. H. 1er Komplementierung/Invertierung) können Sie Folgendes tun:

Da der Wert ExORed mit allen 1s zu einer Umkehrung von Für eine bestimmte Bitbreite führt, können Sie sie mit ExOR invertieren.

In Binary
a=1010 --> this is 0xA or decimal 10
then 
c = 1111 ^ a = 0101 --> this is 0xF or decimal 15
-----------------
In Python
a=10
b=15
c = a ^ b --> 0101
print(bin(c)) # gives '0b101'
0
user11034079

Während die Bearbeitung von Bits einer Ganzzahl nützlich ist, ist dies häufig für Netzwerkprotokolle, die bis auf das Bit festgelegt werden können, die Manipulation längerer Byte-Sequenzen (die nicht einfach in eine Ganzzahl umgewandelt werden können) erforderlich. In diesem Fall ist es nützlich, die Bibliothek bitstring zu verwenden, die bitweise Operationen an Daten ermöglicht, z. Man kann den String 'ABCDEFGHIJKLMNOPQ' als String oder als Hex importieren und ihn bitweise verschieben (oder andere bitweise Operationen ausführen):

>>> import bitstring
>>> bitstring.BitArray(bytes='ABCDEFGHIJKLMNOPQ') << 4
BitArray('0x142434445464748494a4b4c4d4e4f50510')
>>> bitstring.BitArray(hex='0x4142434445464748494a4b4c4d4e4f5051') << 4
BitArray('0x142434445464748494a4b4c4d4e4f50510')
0
Pierz