Python中的float的二进制表示(位不是hex)
如何获得一个32位浮点数的二进制IEEE 754表示string?
例
1.00 – >'00111111100000000000000000000000'
你可以用struct
包来做到这一点:
import struct def binary(num): return ''.join(bin(ord(c)).replace('0b', '').rjust(8, '0') for c in struct.pack('!f', num))
将其打包为networking字节顺序的浮点数,然后将每个结果字节转换为8位二进制表示forms并将它们连接起来:
>>> binary(1) '00111111100000000000000000000000'
编辑 :有一个请求来扩大解释。 我将使用中间variables来扩展它以评论每一步。
def binary(num): # Struct can provide us with the float packed into bytes. The '!' ensures that # it's in network byte order (big-endian) and the 'f' says that it should be # packed as a float. Alternatively, for double-precision, you could use 'd'. packed = struct.pack('!f', num) print 'Packed: %s' % repr(packed) # For each character in the returned string, we'll turn it into its corresponding # integer code point # # [62, 163, 215, 10] = [ord(c) for c in '>\xa3\xd7\n'] integers = [ord(c) for c in packed] print 'Integers: %s' % integers # For each integer, we'll convert it to its binary representation. binaries = [bin(i) for i in integers] print 'Binaries: %s' % binaries # Now strip off the '0b' from each of these stripped_binaries = [s.replace('0b', '') for s in binaries] print 'Stripped: %s' % stripped_binaries # Pad each byte's binary representation's with 0's to make sure it has all 8 bits: # # ['00111110', '10100011', '11010111', '00001010'] padded = [s.rjust(8, '0') for s in stripped_binaries] print 'Padded: %s' % padded # At this point, we have each of the bytes for the network byte ordered float # in an array as binary strings. Now we just concatenate them to get the total # representation of the float: return ''.join(padded)
结果举几个例子:
>>> binary(1) Packed: '?\x80\x00\x00' Integers: [63, 128, 0, 0] Binaries: ['0b111111', '0b10000000', '0b0', '0b0'] Stripped: ['111111', '10000000', '0', '0'] Padded: ['00111111', '10000000', '00000000', '00000000'] '00111111100000000000000000000000' >>> binary(0.32) Packed: '>\xa3\xd7\n' Integers: [62, 163, 215, 10] Binaries: ['0b111110', '0b10100011', '0b11010111', '0b1010'] Stripped: ['111110', '10100011', '11010111', '1010'] Padded: ['00111110', '10100011', '11010111', '00001010'] '00111110101000111101011100001010'
这是一个丑陋的…
>>> import struct >>> bin(struct.unpack('!i',struct.pack('!f',1.0))[0]) '0b111111100000000000000000000000'
基本上,我只是用结构模块将浮点数转换为一个int …
这里使用ctypes
稍微好一点:
>>> import ctypes >>> bin(ctypes.c_uint.from_buffer(ctypes.c_float(1.0)).value) '0b111111100000000000000000000000'
基本上,我构build一个float
并使用相同的内存位置,但我标记为c_uint
。 c_uint
的值是一个python整数,你可以使用内build的bin
函数。
使用bitstring模块find另一个解决scheme。
import bitstring f1 = bitstring.BitArray(float=1.0, length=32) print f1.read('bin')
输出:
00111111100000000000000000000000
把这个问题分解成两个部分,就可以更好地处理这个问题。
首先是将float转换为具有等同位模式的int:
def float32_bit_pattern(value): return sum(ord(b) << 8*i for i,b in enumerate(struct.pack('f', value)))
接下来将int转换为一个string:
def int_to_binary(value, bits): return bin(value).replace('0b', '').rjust(bits, '0')
现在结合起来:
>>> int_to_binary(float32_bit_pattern(1.0), 32) '00111111100000000000000000000000'
为了完整起见,你可以使用numpy来实现:
f = 1.00 int32bits = np.asarray(f, dtype=np.float32).view(np.int32).item() # item() optional
然后可以使用b
格式说明符使用填充来打印此内容
print('{:032b}'.format(int32bits))
浏览了很多类似的问题之后,我写了一些希望做我想做的事情。
f = 1.00 negative = False if f < 0: f = f*-1 negative = True s = struct.pack('>f', f) p = struct.unpack('>l', s)[0] hex_data = hex(p) scale = 16 num_of_bits = 32 binrep = bin(int(hex_data, scale))[2:].zfill(num_of_bits) if negative: binrep = '1' + binrep[1:]
binrep
是结果。 每个部分都会解释。
f = 1.00 negative = False if f < 0: f = f*-1 negative = True
将数字转换为正数(如果为负数),并将variables负数设置为false。 其原因是正负二进制表示之间的区别只是第一位,这是比较简单的方法,而不是在负数的整个过程中发现错误。
s = struct.pack('>f', f) #'?\x80\x00\x00' p = struct.unpack('>l', s)[0] #1065353216 hex_data = hex(p) #'0x3f800000'
s
是二进制f
的hex表示。 但它不是我需要的漂亮的forms。 这就是p进来的地方。这是hex的整数表示。 然后再转换得到一个漂亮的hex。
scale = 16 num_of_bits = 32 binrep = bin(int(hex_data, scale))[2:].zfill(num_of_bits) if negative: binrep = '1' + binrep[1:]
scale
是hex的基数16。 num_of_bits
是32,因为float是32位,所以稍后用它来填充附加的地方,使用0来得到32.从这个问题得到binrep
的代码。 如果数字是负数,只需更改第一位。
我知道这很难看,但我找不到一个好方法,我需要它很快。 欢迎评论。
在我看来,你可以使用.format来表示最简单的位。
我的代码看起来像这样:
def fto32b(flt): # is given a 32 bit float value and converts it to a binary string if isinstance(flt,float): # THE FOLLOWING IS AN EXPANDED REPRESENTATION OF THE ONE LINE RETURN # packed = struct.pack('!f',flt) <- get the hex representation in (!)Big Endian format of a (f) Float # integers = [] # for c in packed: # integers.append(ord(c)) <- change each entry into an int # binaries = [] # for i in integers: # binaries.append("{0:08b}".format(i)) <- get the 8bit binary representation of each int (00100101) # binarystring = ''.join(binaries) <- join all the bytes together # return binarystring return ''.join(["{0:08b}".format(i) for i in [ord(c) for c in struct.pack('!f',flt)]]) return None
输出:
>>> a = 5.0 '01000000101000000000000000000000' >>> b = 1.0 '00111111100000000000000000000000'
其中的一些答案没有像Python 3所写的那样工作,或者没有给出负浮点数的正确表示。 我发现以下为我工作(虽然这给了我需要的64位表示)
def float_to_binary_string(f): def int_to_8bit_binary_string(n): stg=bin(n).replace('0b','') fillstg = '0'*(8-len(stg)) return fillstg+stg return ''.join( int_to_8bit_binary_string(int(b)) for b in struct.pack('>d',f) )
这比被问到的要多一点,但是当我find这个条目的时候,这是我所需要的。 此代码将给出IEEE 754 32位浮点的尾数,基数和符号。
import ctypes def binRep(num): binNum = bin(ctypes.c_uint.from_buffer(ctypes.c_float(num)).value)[2:] print("bits: " + binNum.rjust(32,"0")) mantissa = "1" + binNum[-23:] print("sig (bin): " + mantissa.rjust(24)) mantInt = int(mantissa,2)/2**23 print("sig (float): " + str(mantInt)) base = int(binNum[-31:-23],2)-127 print("base:" + str(base)) sign = 1-2*("1"==binNum[-32:-31].rjust(1,"0")) print("sign:" + str(sign)) print("recreate:" + str(sign*mantInt*(2**base))) binRep(-0.75)
输出:
bits: 10111111010000000000000000000000 sig (bin): 110000000000000000000000 sig (float): 1.5 base:-1 sign:-1 recreate:-0.75