web-dev-qa-db-fra.com

Comment convertir un entier signé en python non signé

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.

55
Lior

En supposant :

  1. Vous avez à l'esprit des représentations en complément de 2; et,
  2. Par (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.

67
Tim Peters

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.

49
Duncan

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.

12
BrenBarn

utilisez simplement abs pour convertir unsigned en python 

 a=-12
b=abs(a)
print(b)

Sortie: 12

1
Hari Prasath

Vous pouvez utiliser la bibliothèque intégrée struct de Python:

Code:

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

Décoder:

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.
  • Dans AMD64 l'architecture int et long sont en 32 bits, vous pouvez donc utiliser i et I au lieu de l et L respectivement. 
0
Benyamin Jafari

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
0
Preeti Duhan