In der Informatik ist ein bitweiser Operator ein Operator, der auf ein oder zwei Bitketten, Bitfeldern, Bitfolgen oder Bitvektoren auf der Ebene der einzelnen Bits angewendet wird. Insbesondere in den Programmiersprachen der C-Familie können Binärzahlen ohne weitere syntaktische Kennzeichnung als Bitfolgen aufgefasst werden.

Die zugrundeliegenden Operationen auf den einzelnen Bits sind schaltungstechnisch die allereinfachsten, und alle höheren Operationen lassen sich auf sie zurückführen. Die bitweisen Operationen werden wegen ihrer geringeren Bedeutung für die Geschwindigkeit eines Computersystems jedoch meist weniger durch Optimierung bevorzugt als die komplexeren arithmetischen Operationen wie Addition und Subtraktion.

Bitweise Operatoren Die Sprechweise bitweise deutet darauf hin, dass die mehrgliedrigen Eingabeoperanden komponentenweise verarbeitet werden. (Sie können natürlich auch eingliedrig sein.) Man kann davon ausgehen, dass bei zweistelligen Operationen verschieden lange Operanden vom Compiler als Fehler angesehen werden.

In vielen Programmiersprachen der C-Familie wird syntaktisch und semantisch zwischen bitweise (= mehrgliedrig und komponentenweise) und logisch (= boolesch = eine einzige Komponente) unterschieden. Letztere werden wegen der naheliegenden Verwechslungsgefahr in diesem Artikel zusätzlich aufgeführt.

NICHT Das bitweise NICHT oder Komplement ist eine einstellige Verknüpfung, die eine logische Negation (Inversion) jedes Bits durchführt. Wird die Bitfolge als Binärzahl aufgefasst, dann ist dies die Bildung des Einerkomplements. Jede 0 wird durch eine 1 ausgetauscht und umgekehrt. Beispiel:

NICHT 0111 = 1000

In vielen Programmiersprachen der C-Familie wird das bitweise NICHT als ~ (Tilde) dargestellt. Im Gegensatz dazu wird beim logischen Operator ! (Ausrufezeichen) für logisches NICHT der gesamte Wert als Boolescher Ausdruck true ≠ 0 oder false = 0 interpretiert. Das logische NICHT ist keine bitweise Operation.

NICHT (bitweise): ~0 = 1 ~1dez = 0dez ~5dez = ~0101bin = 1010bin = 10dez

NICHT (logisch): !false = true !true = false !0 = true !1dez = false !5dez = false

UND mini|Bitweises UND von 4 Bit

Das bitweise UND wird auf zwei Bitfolgen gleicher Länge angewendet und gibt eine Bitfolge derselben Länge zurück, indem es jeweils Bits an der gleichen Stelle (jeweils das erste Bit, jeweils das zweite Bit usw.) mit einem logischen UND (logische Konjunktion) verknüpft. Bei jedem Paar ist das Ergebnisbit 1, falls beide Bits 1 sind, ansonsten 0. Beispiel:

0101 UND 0011 = 0001

In den mit C verwandten Programmiersprachen wird das bitweise UND durch & (kaufmännisches Und, englisch ampersand) dargestellt. Das boolesche Gegenstück dazu, das logische UND, interpretiert jeden seiner zwei Operanden als einen booleschen Wert und wird als && (zwei kaufmännische Und) dargestellt.

Das bitweise UND kann verwendet werden, um eine Bitfolge zu maskieren. Dadurch können Teile eines Bitstrings isoliert werden, und man kann ermitteln, ob ein bestimmtes Bit gesetzt ist oder nicht. Beispiel:

0011

Um herauszufinden, ob das dritte Bit gesetzt ist oder nicht, wird darauf ein bitweises UND mit einer Maske angewendet, die an der dritten Position eine 1 enthält:

0011 UND 0010 = 0010

Da das Ergebnis nicht Null ist, muss das dritte Bit in der ursprünglichen Bitfolge eine 1 gewesen sein. Diese Anwendung des bitweisen UND wird bitweise Maskierung genannt, weil Teile, die nicht geändert werden sollen oder für die Berechnung nicht wichtig sind, ausgeblendet werden.

Das bitweise UND kann mit dem bitweisen NICHT kombiniert werden, um Bits zu löschen. Beispielsweise soll in der Bitfolge 0110 das zweite Bit gelöscht (d. h. auf 0 gesetzt) werden, sodass im Ergebnis 0010 herauskommt.

Dies geschieht, indem wir eine invertierte Maske (die Null muss dafür an der Stelle der zu ändernden Ziffer gesetzt werden) auf unsere Bitfolge anwenden. Invertieren können wir mit dem NICHT-Operator.

NICHT 0100 = 1011

Danach wird die Bitfolge und die Maske mittels UND-Operator verknüpft:

0110 UND 1011 = 0010

Weiterhin ist es mit dem bitweisen UND möglich, eine Binärzahl modulo 2k zu rechnen, indem man sie mit 2k−1 UND-verknüpft. Dadurch werden alle Bits ab der Position von rechts auf 0 gesetzt.

Beispiel: 17 mod 8 = 1 entspricht

010001 (17) UND 000111 (7 = 8−1) = 000001

ODER mini|Bitweises ODER von 4 Bit

Das bitweise ODER wird auf zwei Bitfolgen gleicher Länge angewendet und gibt eine Bitfolge derselben Länge zurück, indem es jeweils Bits an der gleichen Stelle mit einem logischen ODER (logische Disjunktion) verknüpft. Bei jedem Paar ist das Ergebnisbit 0, falls beide Bits 0 sind, ansonsten ist das Ergebnisbit 1. Beispiel:

0101 ODER 0011 = 0111

In den mit C verwandten Programmiersprachen wird das bitweise ODER durch | (senkrechter Strich) dargestellt. Das boolesche Gegenstück dazu, das logische ODER, das seine Operanden als boolesche Werte interpretiert, wird als || (zwei senkrechte Striche) dargestellt.

Das bitweise ODER wird verwendet, wenn mehrere Bits als Flags verwendet werden; die Bits einer einzelnen Binärzahl können jeweils eine eigene boolesche Variable darstellen. Wendet man das bitweise ODER auf einen solchen Binärwert und eine „Maske“ an, die an bestimmten Stellen eine 1 enthält, so erhält man eine neue Bitfolge, in der diese Bits zusätzlich zu den ursprünglich vorhandenen gesetzt sind. Beispiel:

0010

kann als Liste von vier Flags angesehen werden. Das erste, zweite und vierte Flag sind nicht gesetzt (0), das dritte Flag ist gesetzt (1). Das erste Flag kann gesetzt werden, indem man diese Bitfolge mit einer Bitfolge verknüpft, die nur an der ersten Stelle eine 1 hat:

0010 ODER 1000 = 1010

Diese Technik wird eingesetzt, um Speicherplatz zu sparen, wenn Programme sehr viele Boolesche Werte verwalten müssen.

XOR mini|Bitweises exklusives ODER von 4 Bit

Das bitweise exklusive ODER wird auf zwei Bitfolgen der gleichen Länge angewendet und gibt eine Bitfolge derselben Länge zurück, indem es die logische XOR-Operation auf jedem Paar korrespondierender Bits durchführt. Das Ergebnisbit ist 1, falls die zwei Bits unterschiedlich sind, und 0, falls sie gleich sind. Beispiel:

0101 XOR 0011 = 0110

In den mit C verwandten Programmiersprachen wird das bitweise XOR als ^ (Circumflex) dargestellt. Das boolesche Gegenstück dazu, das logische XOR, das seine zwei Operanden jeweils als einen booleschen Wert auffasst, wird als ^^ dargestellt.

In der Assemblersprache wird das bitweise XOR gelegentlich eingesetzt, um den Wert eines Prozessorregisters auf 0 zu setzen. Wendet man XOR auf zwei identische Operanden an, so erhält man immer 0. In vielen Architekturen benötigt diese Operation weniger Rechenzeit, als man für das Laden einer 0 und das Speichern im Register benötigt.

Das bitweise XOR kann auch verwendet werden, um Flags in Bitfolgen umzuschalten. Dazu fasst man den zweiten Operanden als NICHT-„Maske“ auf den ersten Operanden auf, die diejenigen Stellen logisch invertiert, an denen eine 1 steht, und die anderen unverändert lässt. Im Beispiel

0101 XOR 0011 („Maske“) = 0110

wird das dritte und vierte Flag umgeschaltet. Diese Technik kann eingesetzt werden, um Bitfolgen zu manipulieren, die mehrere boolesche Variablen repräsentieren.

Bitweise Verschiebungen Bei den bitweisen Verschiebungen (englisch ) werden die Bits als einzelne Zeichen an einer bestimmten Bit-Position aufgefasst – und nicht als Paare korrespondierender Bits wie in den oben stehenden Operationen. Dabei bedeutet das Kollektiv der Bits bei der arithmetischen Verschiebung eine Binärzahl oder bei der – etwas elementareren – logischen Verschiebung eine Bitkette (resp. eine vorzeichenlose (englisch ) Binärzahl). Der Hauptunterschied besteht in der Behandlung des eventuellen Vorzeichenbits. Schaltungstechnisch können bitweise Verschiebungen und Rotationen um eine beliebige Stellenanzahl in Form von Barrel-Shiftern realisiert werden.

Bei diesen Operationen werden die Binär-Zeichen um eine angegebene Anzahl von Bitpositionen nach links oder rechts verschoben. Die Richtungsangabe wird dabei unabhängig von der Rechnerarchitektur (und deren Endianness) immer in der (big-endian) Standardkonvention des Dualsystems verstanden: Links bedeutet Multiplikation und rechts Division mit einer Zweierpotenz. Register der Prozessoren sowie Datentypen der Programmiersprachen beherbergen eine definierte endliche Anzahl von Bits, weshalb die spezifizierte Anzahl an Bits an einem Ende aus dem Register oder Datum „hinausgeschoben“, während die gleiche Anzahl am anderen Ende „hineingeschoben“ („hereingezogen“) wird.

Auf diese Weise induzieren die bitweisen Verschiebungsoperationen eine Adressierung der Bits innerhalb eines Bytes.

Beispiel

Symbolik: „<<“ (in einigen Sprachen „shl“) Verschieben nach links, um den jeweils dahinter angegebenen Wert „>>“ (in einigen Sprachen „shr“) Verschieben nach rechts, um den jeweils dahinter angegebenen Wert

In Sprachen wie C wird für Rechtsverschiebungen abhängig vom Datentyp und ggf. Vorzeichen entweder mit Nullen (unsigned oder nicht-negativ) oder mit Einsen (signed und kleiner als Null) aufgefüllt. Andere Programmiersprachen (wie z. B. Java) verwenden stattdessen einen eigenen Operator >>>, bei dem stets mit Nullen aufgefüllt wird:

00111100 << 1 = 01111000 00111100 << 2 = 11110000 (signed erzeugt einen arithmetischen Überlauf) 11111100 << 2 = 11110000 (signed ohne arithmetischen Überlauf) 01001111 >> 1 = 00100111 11110000 >> 2 = 11111100 (signed) 11110000 >> 2 = 00111100 (unsigned) 11110000 >>> 2 = 00111100 (signed und unsigned) 01001111 >>> 1 = 00100111 (signed und unsigned)

Eine logische (oder arithmetische) Verschiebung um (Bitpositionen) nach links ist äquivalent zu einer Multiplikation mit , sofern keine 1-Bits hinaus- (bzw. in die Vorzeichenposition hinein)geschoben werden (Ganzzahlüberlauf). Eine arithmetische Verschiebung um (Bitpositionen) nach rechts ist äquivalent zu einer Division durch ; hinausgeschobene 1-Bits gehen verloren.

00001100 << 2 = 00110000

Dieses Verfahren stellt somit eine Alternative zur Multiplikation bzw. Division mit Zweierpotenzen dar. Divisionsergebnisse werden abgeschnitten. Ebenfalls ist es möglich, eine n-Bit-Zahl modulo 2k zu rechnen, indem sie um jeweils n–k nach links und wieder nach rechts verschiebt. Etwas schneller noch kann man die modulo-Berechnung über das bitweise UND mit 2k–1 durchführen.

Eine Verschiebung um 0 Bitpositionen ändert den Wert nicht („identische Abbildung“). Ist für die Verschiebung um Bitpositionen definiert, dann gilt sowohl für (beidesmal) logische wie für (beidesmal) arithmetische Verschiebungen die „Hintereinanderausführung“: ((xyz) >> m) >> n = (xyz) >> (m+n) (signed und unsigned) ((xyz) << m) << n = (xyz) << (m+n) (signed und unsigned) D. h.: Abgesehen von der Einschränkung über die Maximalzahl der Schiebepositionen, ab der das Verhalten (implementierungsabhängig und) undefiniert sein kann, genügt es, das Verhalten der Schiebeoperationen für eine (einzige) Schiebeposition zu definieren.

Logische Verschiebung

mini|Logischer Rechtsshift mini|Logischer Linksshift

Bei einer logischen Verschiebung (englisch ) werden die hinausgeschobenen Bits verworfen und Nullen nachgezogen, unabhängig von Schieberichtung und Vorzeichen. Deshalb sind logische und arithmetische Verschiebung nach links (bis auf die eventuelle Setzung von Flags) identische Operationen. Bei der logischen Verschiebung nach rechts werden jedoch Nullen statt Kopien des Vorzeichenbits eingefügt. Daher wird die logische Verschiebung bei Bitketten oder vorzeichenlosen Binärzahlen eingesetzt, während arithmetische Verschiebungen bei vorzeichenbehafteten Zweierkomplementzahlen verwendet werden.

Arithmetische Verschiebung 184px|mini|Arithmetischer Rechtsshift mini|Arithmetischer Linksshift