Estoy tratando de resolver un desafío en este sitio. Tengo todo correcto, excepto que no puedo convertir correctamente una cadena de bits a su representación entera con signo de 32 bits.

Por ejemplo, tengo esta cadena de bits:

block = '10101010001000101110101000101110'

Mi propia forma de convertir esta cadena de bits en un entero con signo de 32 bits: recuerdo parcialmente de la escuela que el primer bit es el bit de signo. Si es 1 tenemos número negativo y viceversa.

Cuando hago esto, me da el número en base 10. Simplemente lo convierte en base 10:

int(block, 2) #yields 2854414894

Intenté excluir el primer bit y convertir la cadena de bits de 31 longitudes restantes, después de eso verifiqué el primer bit para decidir si este es un número negativo o no:

int(block[1:32], 2) #yields 706931246

Pero la respuesta correcta es -1440552402. ¿Qué operación debo hacer a esta cadena de bits para obtener este entero? ¿Es relevante si el orden de bytes del sistema es little endian o big endian? Mi sistema es poco endian.

2
Bora 12 feb. 2017 a las 00:04

3 respuestas

La mejor respuesta

Tienes razón en que el bit superior determina el signo, pero no es una simple bandera. En cambio, se invierte todo el carácter de los números negativos. Este es un número positivo 1 (en 8 bits):

00000001

Este es un 1 negativo:

11111111

El resultado es que la suma y la resta se "ajustan". Entonces 4 - 1 sería:

0100 - 0001 = 0011

Y entonces 0 - 1 es lo mismo que 1_0000_0000 - 1. El "préstamo" simplemente sale de la parte superior del entero.

La forma general de "negar" un número es "invertir los bits, agregar 1". Esto funciona en ambos sentidos, por lo que puede pasar de positivo a negativo y viceversa.

En su caso, use el '1' inicial para detectar si es necesaria la negación, luego convierta a int, y luego realice los pasos de negación. Sin embargo, tenga en cuenta que debido a que int de Python no es un valor de ancho fijo, hay una bandera interna separada (un Python int no es un número de "32 bits", es un entero de precisión arbitraria, con una representación asignada dinámicamente almacenada de alguna manera que no sea el complemento simple de 2).

block = '10101010001000101110101000101110'
asnum = int(block, 2)
if block[0] == '1':
    asnum ^= 0xFFFFFFFF
    asnum += 1
    asnum = -asnum

print(asnum)
3
aghast 11 feb. 2017 a las 21:20

En python no hay tamaño para los enteros, por lo que nunca obtendrá un valor negativo con un orden superior de 1 bit.

Para "emular" el comportamiento de 32 bits, simplemente haga esto, ya que su valor 2854414894 es> 2**31-1 también conocido como 0x7FFFFFFF:

print(int(block[1:32], 2)-2**31)

Obtendrás

-1440552402
4
Jean-François Fabre 11 feb. 2017 a las 21:14

Debe verificar cuándo el valor de entrada está fuera del rango positivo para enteros con signo de 32 bits:

res = int(block, 2)
if res >= 2**31:
    res -= 2**32

Entonces, primero interpreta el número como un número sin signo , pero cuando nota que el bit de signo se estableció (> = 2 ^ 31), resta 2 ^ 32 para obtener el número negativo.

2
trincot 11 feb. 2017 a las 21:16