简体   繁体   English

如何将二进制(字符串)转换为浮点值?

[英]How to convert a binary (string) into a float value?

I want to convert a binary number into a float number.我想将二进制数转换为浮点数。 Here's an example of a possibility:这是一个可能性的例子:

>>> float(-0b1110)

gives me the correct output:给我正确的输出:

-14.0

Unfortunately, I am working with binary strings , ie, I need something like float('-0b1110') .不幸的是,我正在处理二进制字符串,即,我需要类似float('-0b1110')
However, this doesn't work:但是,这不起作用:

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

I tried to use binascii.a2b_qp(string[, header]) which converts a block of quoted-printable data back to binary and returns the binary data.我尝试使用binascii.a2b_qp(string[, header])它将带引号的可打印数据块转换回二进制并返回二进制数据。 But eventually, I get the same error:但最终,我得到了同样的错误:

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

I understand the cases where the output number is an integer but what if I want to obtain the number 12.546?我理解输出数字是整数的情况,但如果我想获得数字 12.546 怎么办? What would the function call for the binary string look like then?那么对二进制字符串的函数调用会是什么样的呢?

In one of your comments you indicated that the binary number represents a float in 8 byte long IEEE 754 binary64 format.在您的评论之一中,您指出二进制数表示 8 字节长的 IEEE 754 binary64 格式的浮点数。 However that is inconsistent with the -0b1110 value you showed as an example, so I've ignored it and used my own which is in the proper format as example input data for testing the answer shown below.但是,这与您作为示例显示的-0b1110值不一致,因此我忽略了它并使用我自己的正确格式作为示例输入数据来测试下面显示的答案。

Essentially what is done is first the binary string is converted into an integer value, then next into a string of raw bytes which is passed to struct.unpack() for final conversion to a floating point value.基本上所做的是首先将二进制字符串转换为整数值,然后再转换为原始字节字符串,然后将其传递给struct.unpack()以最终转换为浮点值。 The bin_to_float() function shown below drives the process.下面显示的bin_to_float()函数驱动该过程。 Although not illustrated, binary input string arguments can be prefixed with '0b' .虽然没有说明,但二进制输入字符串参数可以以'0b'为前缀。

from codecs import decode
import struct


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)

Output:输出:

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

This works for me.这对我有用。 Tested with Python3.4:用 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

Another option is to do另一种选择是做

from ast import literal_eval

float_str = "-0b101010101"
result = float(literal_eval(float_str))

Unlike the built-in "eval", literal_eval is safe to be run even on user inputs, as it can only parse Python literals - and will not execute expressions, which means it will not call functions as well.与内置的“eval”不同,literal_eval 即使在用户输入上也可以安全运行,因为它只能解析 Python 文字——并且不会执行表达式,这意味着它也不会调用函数。

float(int('-0b1110',0))

That works for me.这对我行得通。

If you have a 64-bit string that represents a floating point number rather than an integer, you can do a three-step conversion - the first step turns the string into an integer, the second converts it into an 8-byte string, and the third re-interprets those bits as a float.如果您有一个代表浮点数而不是整数的 64 位字符串,您可以进行三步转换 - 第一步将字符串转换为整数,第二步将其转换为 8 字节字符串,然后第三个将这些位重新解释为浮点数。

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

Of course you can combine all those steps into a single line.当然,您可以将所有这些步骤合并为一行。

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

You could use eval('') and then cast it as a float if needed.如果需要,您可以使用 eval('') 然后将其转换为浮点数。 Example:例子:

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

You can convert a binary number in string form to an int by setting the base to 2 in the built-in int([x[, base]]) function, however you need to get rid of the 0b first.您可以通过在内置的int([x[, base]])函数中将基数设置为 2 来将字符串形式的二进制数转换为 int,但是您需要先去掉0b You can then pass the result into float() to get your final result:然后,您可以将结果传递给float()以获得最终结果:

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

edit: Apparently getting rid of the 0b is only necessary on Python 2.5 and below, Mark's answer works fine for me on Python 2.6 but here is what I see on Python 2.5:编辑:显然只有在 Python 2.5 及更低版本上才需要摆脱0b ,Mark 的回答在 Python 2.6 上对我来说效果很好,但这是我在 Python 2.5 上看到的:

>>> int('-0b1110', 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 2: '-0b1110'
def bin_to_float(binary):
    di = binary.find('.')
    if di == -1:
        return int(binary,2)
    else:
        whole = binary[:di] or '0'
        fraction = binary [di+1:] or '0'
        return int(whole,2) + int(whole,2)/abs(int(whole,2)) * int(fraction,2) / 2** len(fraction)

samples = [
    '-0b1110.010101011',
    '-0b1001110',
    '101',
    '0b1110010.11010111011',
    '1100.',
    '-00011',
    '+0b1100.0011',
]

for binary in samples:
    print(binary,'=',bin_to_float(binary))

Returns退货

-0b1110.010101011 = -14.333984375
-0b1001110 = -78
101 = 5
0b1110010.11010111011 = 114.84130859375
1100. = 12.0
-00011 = -3
+0b1100.0011 = 12.1875

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM