web-dev-qa-db-fra.com

opération au niveau des bits unaire ~ (inverti)

Je suis un peu confus par l'opérateur ~. Le code va en dessous:

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

Comment fonctionne ~?

Je pensais que ~a serait quelque chose comme:

0001 = a
1110 = ~a 

pourquoi pas?

46
Alcott

Tu as tout à fait raison. C'est un artefact de complément à deux représentation entière.

En 16 bits, 1 est représenté par 0000 0000 0000 0001. Inversé, vous obtenez 1111 1111 1111 1110, qui est -2. De même, 15 est 0000 0000 0000 1111. Inversé, vous obtenez 1111 1111 1111 0000, qui est -16.

En général, ~n = -n - 1

46
NullUserException

L'opérateur '~' est défini comme suit: "L'inversion binaire de x correspond à - (x + 1). Elle s'applique uniquement aux nombres entiers." Python Doc - 5.5

La partie importante de cette phrase est que cela est lié aux «nombres entiers» (également appelés entiers). Votre exemple représente un nombre de 4 bits.

'0001' = 1 

La plage entière d'un nombre de 4 bits est '-8..0..7'. D'autre part, vous pouvez utiliser des «entiers non signés», qui n'incluent pas les nombres négatifs et la plage de votre nombre de 4 bits serait «0..15».

Puisque Python fonctionne sur des entiers, le comportement que vous avez décrit est attendu. Les entiers sont représentés par un complément à deux. Dans le cas d'un nombre de 4 bits, cela ressemble à ce qui suit. 

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

Python utilise 32 bits pour la représentation entière si vous avez un système d'exploitation 32 bits. Vous pouvez vérifier le plus grand entier avec:

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

Dans le cas où vous voudriez qu'un entier non signé soit retourné pour vous, un nombre de 4 bits que vous devez masquer.

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

(~a & 0xF) # returns 14

Si vous voulez obtenir une plage de numéros de 8 bits non signés (0..255), utilisez plutôt:

(~a & 0xFF) # returns 254
27
sebs

On dirait que j'ai trouvé une solution plus simple qui fait ce que l'on souhaite:

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

Vous pouvez également utiliser des ints non signés (provenant par exemple du paquet numpy) pour obtenir le comportement attendu.

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

L'opérateur d'inversion unaire de Python ~ x = - (x + 1), et ceci est identique à l'activation de chaque bit en mémoire: 

par exemple

>>> 0b110    # an integer defined with a binary literal
# 0|1,1,0    = in sign|magnitude form
# +|4,2,0    = each bit's contribution to the int
# +1*(4+2+0) =>
6            

>>> bin(~0b110) # get the binary representation of inverted 0b110
# 1|001         = each bit simply inverted (invert sign bit too)
# -|4+2+0 +1    = each bit's contribution to the int, ‡See note
# -1*(4+2+0+1)  = -7    (the answer we want that represents each bit flipped)
# -0b111        = binary representation of -7
-0b111          = it resembles 1|111 but it in memory it is actually 1|001

-0b111est1|001en mémoire. Vous ne devez pas interpréter une représentation de nombre binaire -ve comme ce qui est stocké en mémoire, contrairement à un nombre binaire positif. 

‡ Remarque: Les nombres négatifs dans les fichiers binaires sont comptés à l’arrière. Ainsi, chaque position de -ve bit n’est comptée que dans la composition du int s’il s’agit de 0 et vous devez ajouter -1 au résultat final:

# in-memory  = int  (displayed as)
1|11..111    = -1   (-0b1)
1|11..110    = -2   (-0b10)
1|11..101    = -3   (-0b11)
1|11..100    = -4   (-0b100)
# and so on...
0
Riaz Rizvi