92 Stimmen

bitweise Operation unär ~ (invertieren)

Ich bin ein wenig verwirrt von der ~ Betreiber. Der Code steht unten:

a = 1
~a  #-2
b = 15
~b  #-16

Wie funktioniert ~ Arbeit machen?

Ich dachte, ~a wäre etwa so:

0001 = a
1110 = ~a 

warum nicht?

77voto

NullUserException Punkte 80891

Sie haben völlig recht. Es ist ein Artefakt der Zweierkomplement Ganzzahlige Darstellung.

In 16 Bit wird 1 dargestellt als 0000 0000 0000 0001 . Invertiert erhält man 1111 1111 1111 1110 was -2 ist. 15 ist dementsprechend 0000 0000 0000 1111 . Invertiert erhält man 1111 1111 1111 0000 was -16 ist.

Generell, ~n = -n - 1

38voto

sebs Punkte 4314

Der Operator '~' ist definiert als: "Die bitweise Inversion von x ist definiert als -(x+1). Sie gilt nur für ganze Zahlen." Python Doc - 5.5

Der wichtige Teil dieses Satzes ist, dass es sich um "ganze Zahlen" (auch Integer genannt) handelt. Ihr Beispiel stellt eine 4-Bit-Zahl dar.

'0001' = 1 

Der ganzzahlige Bereich einer 4-Bit-Zahl ist '-8..0..7'. Andererseits könnten Sie "ganze Zahlen ohne Vorzeichen" verwenden, die keine negativen Zahlen enthalten, und der Bereich für Ihre 4-Bit-Zahl wäre "0..15".

Da Python mit ganzen Zahlen arbeitet, ist das von Ihnen beschriebene Verhalten zu erwarten. Ganzzahlen werden im Zweierkomplement dargestellt. Im Falle einer 4-Bit-Zahl sieht dies wie folgt aus.

 7 = '0111'
 0 = '0000'
-1 = '1111'
-8 = '1000'

Python verwendet 32bit für die Integer-Darstellung, falls Sie ein 32-bit Betriebssystem haben. Sie können die größte Ganzzahl mit überprüfen:

sys.maxint # (2^31)-1 for my system

Wenn Sie eine vorzeichenlose Ganzzahl für eine 4-Bit-Zahl zurückerhalten möchten, müssen Sie diese maskieren.

'0001' = a   # unsigned '1' / integer '1'
'1110' = ~a  # unsigned '14' / integer -2

(~a & 0xF) # returns 14

Wenn Sie stattdessen einen vorzeichenlosen 8-Bit-Zahlenbereich (0..255) erhalten möchten, verwenden Sie einfach:

(~a & 0xFF) # returns 254

29voto

user1919695 Punkte 301

Es sieht so aus, als hätte ich eine einfachere Lösung gefunden, die das Gewünschte bewirkt:

uint8: x ^ 0xFF
uint16: x ^ 0xFFFF
uint32: x ^ 0xFFFFFFFF
uint64: x ^ 0xFFFFFFFFFFFFFFFF

8voto

user1747134 Punkte 2232

Sie könnten auch vorzeichenlose Ints (z. B. aus dem Numpy-Paket) verwenden, um das erwartete Verhalten zu erreichen.

>>> import numpy as np
>>> bin( ~ np.uint8(1))
'0b11111110'

1voto

fjab Punkte 79

Das Problem ist, dass die Zahl, die durch das Ergebnis der Anwendung von ~ dargestellt wird, nicht genau definiert ist, da sie von der Anzahl der Bits abhängt, die zur Darstellung des ursprünglichen Wertes verwendet werden. Zum Beispiel:

5 = 101
~5 = 010 = 2

5 = 0101
~5 = 1010 = 10

5 = 00101
~5 = 11010 = 26

Das Zweierkomplement von ~5 ist jedoch in allen Fällen gleich:

two_complement(~101) = 2^3 - 2 = 6
two_complement(~0101) = 2^4 - 10 = 6
two_complement(~00101) = 2^5 - 26 = 6

Und da das Zweierkomplement zur Darstellung negativer Werte verwendet wird, ist es sinnvoll, ~5 als den negativen Wert, -6, seines Komplements zu betrachten.

Um zu diesem Ergebnis zu kommen, müssen wir also formal gesehen folgendes tun:

  1. gespiegelte Nullen und Einsen (das ist gleichbedeutend mit dem Einerkomplement)
  2. Zweierkomplement genommen
  3. angewandtes negatives Vorzeichen

und wenn x eine n-stellige Zahl ist:

~x = - two_complement(one_complement(x)) = - two_complement(2^n - 1 - x) = - (2^n - (2^n - 1 - x)) = - (x + 1)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X