Disons que j'ai ce numéro i = -6884376
. Comment est-ce que je me réfère à lui comme à une variable non signée? Quelque chose comme (unsigned long)i
en C.
En supposant :
(unsigned long)
vous moyenne entier de 32 bits non signé,alors il vous suffit d’ajouter 2**32 (or 1 << 32)
à la valeur négative.
Par exemple, appliquez ceci à -1:
>>> -1
-1
>>> _ + 2**32
4294967295L
>>> bin(_)
'0b11111111111111111111111111111111'
L'hypothèse n ° 1 signifie que vous souhaitez que -1 soit considéré comme une chaîne solide de 1 bits, et l'hypothèse n ° 2 signifie que vous en voulez 32.
Personne d'autre que vous ne peut dire quelles sont vos suppositions cachées. Si, par exemple, vous avez en tête des représentations avec complément à 1, vous devez alors appliquer l'opérateur préfixe ~
. Les entiers Python travaillent dur pour donner l’illusion d’utiliser une représentation du complément à 2 infiniment large (comme le complément à 2, mais avec un nombre infini de "bits de signe").
Et pour dupliquer ce que fait le compilateur de la plate-forme C, vous pouvez utiliser le module ctypes
:
>>> import ctypes
>>> ctypes.c_ulong(-1) # stuff Python's -1 into a C unsigned long
c_ulong(4294967295L)
>>> _.value
4294967295L
unsigned long
du C se trouve être 4 octets sur la boîte qui a exécuté cet exemple.
Pour obtenir la valeur équivalente à votre conversion C, bit par bit et avec le masque approprié. par exemple. si unsigned long
est 32 bits:
>>> i = -6884376
>>> i & 0xffffffff
4288082920
ou si c'est 64 bits:
>>> i & 0xffffffffffffffff
18446744073702667240
Sachez cependant que même si cela vous donne la valeur que vous auriez en C, il s’agit toujours d’une valeur signée. Tous les calculs ultérieurs peuvent donc donner un résultat négatif et vous devrez continuer à appliquer le masque pour simuler une résolution 32 ou 64. calcul de bits.
Cela fonctionne car, bien que Python semble stocker tous les nombres sous forme de signe et d'amplitude, les opérations au niveau des bits sont définies comme travaillant sur des valeurs de complément à deux. C stocke les nombres entiers par deux, mais avec un nombre de bits fixe. Les opérateurs binaires Python agissent sur deux valeurs complémentaires mais comme si elles avaient un nombre infini de bits: pour les nombres positifs, elles s'étendent de gauche à l'infini avec des zéros, mais les nombres négatifs s'étendent à gauche avec des uns. L'opérateur &
transformera cette chaîne de uns vers la gauche en zéros et vous laissera uniquement les bits qui auraient pu tenir dans la valeur C.
L'affichage des valeurs en hexa peut rendre cela plus clair (et j'ai récrit la chaîne de f comme expression pour montrer que nous sommes intéressés par 32 ou 64 bits):
>>> hex(i)
'-0x690c18'
>>> hex (i & ((1 << 32) - 1))
'0xff96f3e8'
>>> hex (i & ((1 << 64) - 1)
'0xffffffffff96f3e8L'
Pour une valeur 32 bits en C, les nombres positifs vont jusqu'à 2147483647 (0x7fffffff) et les nombres négatifs ont le bit supérieur défini allant de -1 (0xffffffff) à -2147483648 (0x80000000). Pour les valeurs qui correspondent entièrement au masque, nous pouvons inverser le processus en Python en utilisant un masque plus petit pour supprimer le bit de signe, puis en soustrayant le bit de signe:
>>> u = i & ((1 << 32) - 1)
>>> (u & ((1 << 31) - 1)) - (u & (1 << 31))
-6884376
Ou pour la version 64 bits:
>>> u = 18446744073702667240
>>> (u & ((1 << 63) - 1)) - (u & (1 << 63))
-6884376
Ce processus inverse laissera la valeur inchangée si le bit de signe est 0, mais ce n'est évidemment pas un inverse, car si vous commencez avec une valeur qui ne rentre pas dans la taille du masque, ces bits disparaissent.
Python n'a pas de types intégrés non signés. Vous pouvez utiliser des opérations mathématiques pour calculer un nouveau int représentant la valeur que vous obtiendriez en C, mais il n'y a pas de "valeur non signée" d'un int Python. Le Python int est une abstraction d'une valeur entière, pas un accès direct à un entier de taille fixe.
utilisez simplement abs pour convertir unsigned en python
a=-12
b=abs(a)
print(b)
Sortie: 12
struct
de Python:import struct
i = -6884376
print('{0:b}'.format(i))
packed = struct.pack('>l', i) # Packing a long number.
unpacked = struct.unpack('>L', packed)[0] # Unpacking a packed long number to unsigned long
print(unpacked)
print('{0:b}'.format(unpacked))
En dehors:
-11010010000110000011000
4288082920
11111111100101101111001111101000
dec_pack = struct.pack('>L', unpacked) # Packing an unsigned long number.
dec_unpack = struct.unpack('>l', dec_pack)[0] # Unpacking a packed unsigned long number to long (revert action).
print(dec_unpack)
En dehors:
-6884376
[REMARQUE]:
>
est une opération BigEndian.l
est long.L
est unsigned long.AMD64
l'architecture int
et long
sont en 32 bits, vous pouvez donc utiliser i
et I
au lieu de l
et L
respectivement. python ne possède pas de fonction permettant de convertir int en unsigned int. Au lieu de cela, sa portée est longue.
>>> val = 9223372036854775807 (maximum value of int 64)
>>> type(val)
<type 'int'>
>>> val += 1
>>> type(val)
<type 'long'>
En augmentant la valeur de val de 1, je dépasse la limite d'un entier signé de 64 bits et la valeur est convertie en long. Si Python avait utilisé ou converti un entier non signé, val aurait quand même été un entier. Ou pas longtemps.
Les entiers signés sont représentés par un bit, généralement le bit le plus significatif, étant mis à 0 pour les nombres positifs ou à 1 pour les nombres négatifs. Ce que val & 0xff fait est en réalité val & 0x000000ff (sur une machine 32 bits). En d'autres termes, le bit signé est mis à 0 et une valeur non signée est émulée.
Un exemple:
>>> val = -1
>>> val & 0xff
255