¿Cómo convertir un binario (cadena) en un valor flotante?

Quiero convertir un número binario en un número flotante. Aquí hay un ejemplo de una posibilidad:

>>> float(-0b1110) 

Me da la salida correcta:

 -14.0 

Desafortunadamente, estoy trabajando con cadenas binarias, es decir, necesito algo como float('-0b1110') .
Sin embargo, esto no funciona:

 >>> float('-0b1110') Traceback (most recent call last): File "", line 1, in  ValueError: invalid literal for float(): -0b1110 

Intenté usar binascii.a2b_qp(string[, header]) que convierte un bloque de datos imprimibles entre comillas de nuevo a binarios y devuelve los datos binarios. Pero al final me sale el mismo error:

 >>> float(binascii.a2b_qp('-0b1110')) Traceback (most recent call last): File "", line 1, in  ValueError: invalid literal for float(): -0b1110 

Entiendo los casos en los que el número de salida es un número entero, pero ¿qué sucede si deseo obtener el número 12.546? ¿Cómo se vería la función de la cadena binaria entonces?

Otra opción es hacer.

 from ast import literal_eval float_str = "-0b101010101" result = float(literal_eval(float_str)) 

A diferencia de la “eval” incorporada, literal_eval es seguro para ejecutarse incluso en las entradas del usuario, ya que solo puede analizar los literales de Python, y no ejecutará expresiones, lo que significa que no llamará a las funciones también.

En uno de sus comentarios, indicó que el número binario representa una flotación en formato binario IEEE 754 de 8 bytes de longitud. Sin embargo, eso es incoherente con el valor -0b1110 que mostró como ejemplo, así que lo ignoré y utilicé el mío, que está en el formato adecuado como datos de entrada de ejemplo para probar la respuesta que se muestra a continuación.

Esencialmente, lo que se hace es primero que la cadena binaria se convierta en un valor entero, luego a continuación en una cadena de bytes sin procesar que se pasa a struct.unpack() para la conversión final a un valor de punto flotante. La función bin_to_float() que se muestra a continuación controla el proceso. Aunque no se ilustra, los argumentos de cadena de entrada binarios se pueden prefijar con '0b' .

 from codecs import decode import struct import sys def bin_to_float(b): """ Convert binary string to a float. """ bf = int_to_bytes(int(b, 2), 8) # 8 bytes needed for IEEE 754 binary64. return struct.unpack('>d', bf)[0] def int_to_bytes(n, length): # Helper function """ Int/long to byte string. Python 3.2+ has a built-in int.to_bytes() method that could be used instead, but the following works in earlier versions including 2.x. """ return decode('%%0%dx' % (length << 1) % n, 'hex')[-length:] def float_to_bin(value): # For testing. """ Convert float to 64-bit binary string. """ [d] = struct.unpack(">Q", struct.pack(">d", value)) return '{:064b}'.format(d) if __name__ == '__main__': for f in 0.0, 1.0, -14.0, 12.546, 3.141593: print('Test value: %f' % f) binary = float_to_bin(f) print(' float_to_bin: %r' % binary) floating_point = bin_to_float(binary) # Round trip. print(' bin_to_float: %f\n' % floating_point) 

Salida:

 Test value: 0.000000 float_to_bin: '0000000000000000000000000000000000000000000000000000000000000000' bin_to_float: 0.000000 Test value: 1.000000 float_to_bin: '0011111111110000000000000000000000000000000000000000000000000000' bin_to_float: 1.000000 Test value: -14.000000 float_to_bin: '1100000000101100000000000000000000000000000000000000000000000000' bin_to_float: -14.000000 Test value: 12.546000 float_to_bin: '0100000000101001000101111000110101001111110111110011101101100100' bin_to_float: 12.546000 Test value: 3.141593 float_to_bin: '0100000000001001001000011111101110000010110000101011110101111111' bin_to_float: 3.141593 
 float(int('-0b1110',0)) 

Funciona para mi.

Si tiene una cadena de 64 bits que representa un número de punto flotante en lugar de un número entero, puede hacer una conversión de tres pasos: el primer paso convierte la cadena en un número entero, el segundo la convierte en una cadena de 8 bytes, y el tercero reinterpreta esos bits como un flotador.

 >>> import struct >>> s = '0b0100000000101001000101111000110101001111110111110011101101100100' >>> q = int(s, 0) >>> b8 = struct.pack('Q', q) >>> struct.unpack('d', b8)[0] 12.546 

Por supuesto, puedes combinar todos esos pasos en una sola línea.

 >>> s2 = '0b1100000000101100000000000000000000000000000000000000000000000000' >>> struct.unpack('d', struct.pack('Q', int(s2, 0)))[0] -14.0 

Esto funciona para mi Probado con Python3.4:

 def float_to_bin(num): return bin(struct.unpack('!I', struct.pack('!f', num))[0])[2:].zfill(32) def bin_to_float(binary): return struct.unpack('!f',struct.pack('!I', int(binary, 2)))[0] float_to_bin(bin_to_float(float_to_bin(123.123))) == float_to_bin(123.123) >>> True 

Podría usar eval (”) y luego lanzarlo como un flotador si es necesario. Ejemplo:

 >> eval('-0b1110') -14 >> float(eval('-0b1110')) -14.0 

Puede convertir un número binario en forma de cadena a un int configurando la base a 2 en la función int([x[, base]]) integrada int([x[, base]]) , sin embargo, primero debe deshacerse del 0b . Luego puedes pasar el resultado a float() para obtener tu resultado final:

 >>> s = '-0b1110' >>> float(int(s.replace('0b', ''), 2)) -14.0 

edición: Aparentemente, deshacerse de 0b solo es necesario en Python 2.5 y más abajo, la respuesta de Mark funciona bien para mí en Python 2.6, pero esto es lo que veo en Python 2.5:

 >>> int('-0b1110', 2) Traceback (most recent call last): File "", line 1, in  ValueError: invalid literal for int() with base 2: '-0b1110'