it-swarm.com.de

Binäre Darstellung von float in Python (bits not hex)

Wie erhalte ich den String als binäre IEEE 754-Darstellung eines 32-Bit-Floats?

Beispiel

1.00 -> '00111111100000000000000000000000'

46

Sie können dies mit dem Paket struct tun:

import struct
def binary(num):
    return ''.join(bin(ord(c)).replace('0b', '').rjust(8, '0') for c in struct.pack('!f', num))

Das packt es als ein Netzwerk-Byte-geordnetes Float und konvertiert dann jedes der resultierenden Bytes in eine 8-Bit-Binärdarstellung und verkettet sie:

>>> binary(1)
'00111111100000000000000000000000'

Edit: Es wurde um eine Erweiterung der Erklärung gebeten. Ich werde dies mit Zwischenvariablen erweitern, um jeden Schritt zu kommentieren.

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)

Und das Ergebnis für ein paar Beispiele:

>>> 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'
53
Dan Lecocq

Hier ist eine hässliche ...

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

Grundsätzlich habe ich nur das struct-Modul verwendet, um den float in einen int ...


Hier ist eine etwas bessere mit ctypes:

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

Grundsätzlich konstruiere ich ein float und verwende den gleichen Speicherort, aber ich tagge ihn als c_uint. Der Wert von c_uint Ist eine python Ganzzahl, für die Sie die eingebaute Funktion bin verwenden können.

29
mgilson

Mit dem Bitstring Modul wurde eine andere Lösung gefunden.

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

Ausgabe:

00111111100000000000000000000000
20

Dieses Problem wird sauberer gelöst, indem es in zwei Teile geteilt wird.

Die erste besteht darin, das float in ein int mit dem entsprechenden Bitmuster umzuwandeln:

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

Als nächstes konvertieren Sie das int in einen String:

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

Kombiniere sie jetzt:

>>> int_to_binary(float32_bit_pattern(1.0), 32)
'00111111100000000000000000000000'
8
Mark Ransom

Der Vollständigkeit halber können Sie dies mit numpy erreichen, indem Sie:

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

Sie können dies dann mit dem Formatbezeichner b ausfüllen

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

Nachdem ich viele ähnliche Fragen durchgesehen habe, habe ich etwas geschrieben, das hoffentlich das tut, was ich wollte.

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 ist das Ergebnis. Jeder Teil wird erklärt.


f = 1.00
negative = False
if f < 0:
    f = f*-1
    negative = True

Wandelt die Zahl in eine positive um, wenn sie negativ ist, und setzt die Variable negativ auf falsch. Der Grund dafür ist, dass der Unterschied zwischen positiven und negativen Binärdarstellungen nur im ersten Bit liegt, und dies war der einfachere Weg, als herauszufinden, was falsch läuft, wenn der gesamte Prozess mit negativen Zahlen ausgeführt wird.


s = struct.pack('>f', f)                          #'?\x80\x00\x00'
p = struct.unpack('>l', s)[0]                     #1065353216
hex_data =  hex(p)                                #'0x3f800000'

s ist eine hexadezimale Darstellung der Binärdatei f. es ist jedoch nicht in der hübschen Form, die ich brauche. Das ist, wo p hereinkommt. Es ist die int-Darstellung des Hexs. Und dann noch eine Konvertierung, um ein hübsches Hex zu bekommen.


scale = 16
num_of_bits = 32
binrep = bin(int(hex_data, scale))[2:].zfill(num_of_bits)
if negative:
    binrep = '1' + binrep[1:]

scale ist die Basis 16 für das Hex. num_of_bits ist 32, da float 32 Bit ist, wird es später verwendet, um die zusätzlichen Stellen mit 0 zu füllen, um zu 32 zu gelangen. Erhielt den Code für binrep von diese Frage . Wenn die Zahl negativ war, ändern Sie einfach das erste Bit.


Ich weiß, das ist hässlich, aber ich habe keinen guten Weg gefunden und brauchte ihn schnell. Kommentare sind willkommen.

Dies ist etwas mehr als verlangt, aber es war das, was ich brauchte, als ich diesen Eintrag fand. Dieser Code gibt die Mantisse, die Basis und das Vorzeichen des 32-Bit-Floats nach IEEE 754 an.

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)

ausgabe:

bits: 10111111010000000000000000000000
sig (bin): 110000000000000000000000
sig (float): 1.5
base:-1
sign:-1
recreate:-0.75
1
johnml1135

Einige dieser Antworten funktionierten nicht wie mit Python 3 geschrieben oder gaben nicht die richtige Darstellung für negative Gleitkommazahlen an. Ich fand, dass das Folgende für mich funktioniert (obwohl dies 64-Bit ergibt) Darstellung was ich brauchte)

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) )
0
dkhammond

Sie können das .format für die einfachste Darstellung von Bits meiner Meinung nach verwenden:

mein Code würde ungefähr so ​​aussehen:

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

Ausgabe:

>>> a = 5.0
'01000000101000000000000000000000'
>>> b = 1.0
'00111111100000000000000000000000'
0
Robert Hughes