87 votes

Représentation binaire d'un float en Python (bits non hex)

Comment obtenir la chaîne sous forme de représentation binaire IEEE 754 d'un flottant 32 bits ?

Exemple

1.00 -> '00111111100000000000000000000000'

85voto

Dan Lecocq Points 1500

Vous pouvez le faire avec le struct paquet :

import struct
def binary(num):
    return ''.join('{:0>8b}'.format(c) for c in struct.pack('!f', num))

Il l'empaquette sous forme de flottant ordonné par octets en réseau, puis convertit chacun des octets résultants en une représentation binaire de 8 bits et les concatène :

>>> binary(1)
'00111111100000000000000000000000'

Editar : Il y a eu une demande pour développer l'explication. Je vais l'étendre en utilisant des variables intermédiaires pour commenter chaque étape.

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)

Et le résultat pour quelques exemples :

>>> 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'

40voto

mgilson Points 92954

En voilà une moche...

>>> import struct
>>> bin(struct.unpack('!i',struct.pack('!f',1.0))[0])
'0b111111100000000000000000000000'

En gros, j'ai juste utilisé le module struct pour convertir le float en int ...


En voici une légèrement meilleure qui utilise ctypes :

>>> import ctypes
>>> bin(ctypes.c_uint.from_buffer(ctypes.c_float(1.0)).value)
'0b111111100000000000000000000000'

En gros, je construis un float et utiliser le même emplacement de mémoire, mais je le marque comme une c_uint . En c_uint est un nombre entier python que vous pouvez utiliser avec la fonction intégrée bin fonction sur.

30voto

Alan Points 1636

J'ai trouvé une autre solution en utilisant le chaîne de bits module.

import bitstring
f1 = bitstring.BitArray(float=1.0, length=32)
print(f1.bin)

Sortie :

00111111100000000000000000000000

15voto

Eric Points 36290

Par souci d'exhaustivité, vous pouvez réaliser cela avec numpy en utilisant :

f = 1.00
int32bits = np.asarray(f, dtype=np.float32).view(np.int32).item()  # item() optional

Vous pouvez ensuite l'imprimer, avec un remplissage, en utilisant la fonction b spécificateur de format

print('{:032b}'.format(int32bits))

10voto

Mark Ransom Points 132545

Ce problème est traité plus proprement en le divisant en deux parties.

La première consiste à convertir le flottant en un int avec le schéma binaire équivalent :

import struct
def float32_bit_pattern(value):
    return sum(ord(b) << 8*i for i,b in enumerate(struct.pack('f', value)))

Python 3 ne nécessite pas ord pour convertir les octets en nombres entiers, donc vous devez simplifier un peu ce qui précède :

def float32_bit_pattern(value):
    return sum(b << 8*i for i,b in enumerate(struct.pack('f', value)))

Ensuite, convertissez l'int en une chaîne de caractères :

def int_to_binary(value, bits):
    return bin(value).replace('0b', '').rjust(bits, '0')

Maintenant, combinez-les :

>>> int_to_binary(float32_bit_pattern(1.0), 32)
'00111111100000000000000000000000'

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X