Python преобразует число с плавающей точкой в ​​32 бита ieee [duplicate]

Эта проблема может быть решена путем правильной установки *off (четвертый параметр my_read()).

Вам нужно возвращать счет в первый раз и ноль со второго раза вперед.

if(*off == 0) {
    while (msg[count] != 0) {
        put_user(msg[count], buff++);
        count++;
        (*off)++;
    }
    return count;
}
else
return 0;
42
задан kjo 27 November 2015 в 15:09
поделиться

9 ответов

Вы можете сделать это с пакетом struct:

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

. Он упаковывает его в виде байтового упорядоченного байта, а затем преобразует каждый из полученных байтов в 8-битное двоичное представление и конкатенирует их:

>>> binary(1)
'00111111100000000000000000000000'

Изменить: Был запрос на расширение объяснения. Я буду расширять это, используя промежуточные переменные, чтобы прокомментировать каждый шаг.

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'
48
ответ дан Dan Lecocq 18 August 2018 в 04:24
поделиться
  • 1
    @MarkRansom - возможно, вы правы, но похоже, что существует множество операций с строкой, которые выполняются для каждого бита, который не нужно делать ... – mgilson 8 May 2013 в 16:59
  • 2
    Я согласен с @mgilson - я предпочитаю его решение, но с одним финальным replace и rjust до 32 (или 64), а не по одному для каждого байта. – Dan Lecocq 8 May 2013 в 17:01
  • 3
    @MarkRansom: bin(struct.unpack('!Q', struct.pack('!d', -1.))[0])[2:].zfill(64) работает для удвоений (64-битные поплавки). – jfs 8 May 2013 в 17:46
  • 4
    Для Python 3 вы должны опустить вызов ord (), поскольку pack () возвращает объект байтов, который дает целые числа непосредственно при повторении. – Rob Smallshire 25 February 2014 в 11:57
  • 5
    @ 0xAffe, обновленный с более подробным объяснением. – Dan Lecocq 13 November 2014 в 18:45

После просмотра многих похожих вопросов я написал что-то, что, надеюсь, сделает то, что я хотел.

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

Преобразует число в положительное, если отрицательное, и устанавливает переменную отрицательную в значение false. Причина этого заключается в том, что разница между положительными и отрицательными двоичными представлениями находится только в первом бите, и это был более простой способ, чем выяснить, что происходит не так, когда весь процесс обрабатывается с отрицательными числами.


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

s является шестнадцатеричным представлением двоичного файла f. это, однако, не в симпатичной форме, в которой я нуждаюсь. То, где p входит. Это int-представление шестнадцатеричных s. А затем другое преобразование, чтобы получить симпатичный гекс.


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

scale является базой 16 для шестнадцатеричного. num_of_bits равно 32, так как float 32 бита, он используется позже, чтобы заполнить дополнительные места 0, чтобы добраться до 32. Получил код для binrep из этого вопроса . Если число было отрицательным, просто измените первый бит.


Я знаю, что это уродливо, но я не нашел приятного пути, и мне это было нужно быстро. Комментарии приветствуются.

2
ответ дан Community 18 August 2018 в 04:24
поделиться
  • 1
    bin(struct.unpack('!I', struct.pack('!f', -1.))[0])[2:].zfill(32) поддерживает положительные / отрицательные поплавки. Чтобы улучшить производительность, вы можете изменить b2a_bin(struct.pack('!f', -1.)) , чтобы принимать поплавки напрямую. – jfs 8 May 2013 в 17:34

Некоторые из этих ответов не работали так, как написано с 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) )
0
ответ дан dkhammond 18 August 2018 в 04:24
поделиться

Для полноты вы можете добиться этого с помощью numpy, используя:

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

Затем вы можете распечатать это с помощью дополнения, используя спецификатор формата b

print('{:032b}'.format(int32bits))
5
ответ дан Eric 18 August 2018 в 04:24
поделиться
  • 1
    немного опрятный: int32bits = np.float32(1.0).view(np.int32) – Aditya Sriram 7 July 2017 в 03:33
  • 2
    Еще нужно .item(), если вам действительно нужен python int – Eric 8 July 2017 в 21:00
  • 3
    Да, это верно. В противном случае у вас есть объект np.int32 – Aditya Sriram 8 July 2017 в 21:03
  • 4
    все еще аккуратно: int32bits = np.float32(1.0).view(np.int32).item() :) – Aditya Sriram 8 July 2017 в 21:04
  • 5
    int32bits = np.float32 (-3.03) .view (np.uint32) .item (), чтобы поместить знак только один раз – rarias 25 August 2017 в 21:48

Это немного больше, чем было задано, но это было то, что мне нужно, когда я нашел эту запись. Этот код предоставит мантиссе, базу и знак 32-битного поплавка IEEE 754.

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
0
ответ дан johnml1135 18 August 2018 в 04:24
поделиться

Эта проблема более корректно обрабатывается, разбивая ее на две части.

Первым является преобразование float в int с эквивалентным битовым шаблоном:

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

Next преобразуйте int в строку:

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

Теперь соедините их:

>>> int_to_binary(float32_bit_pattern(1.0), 32)
'00111111100000000000000000000000'
8
ответ дан Mark Ransom 18 August 2018 в 04:24
поделиться
  • 1
    float32_bit_pattern можно определить как lambda x: int.from_bytes(struct.pack("f", x), byteorder="little") на Python 3.2+ – Janus Troelsen 30 September 2014 в 17:25

Вот уродливый ...

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

В принципе, я просто использовал структурный модуль для преобразования float в int ...


Вот немного лучше, используя ctypes:

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

В принципе, я создаю float и использую ту же ячейку памяти, но я помещаю ее как c_uint. Значение c_uint представляет собой целое число python, на которое вы можете использовать встроенную функцию bin.

24
ответ дан mgilson 18 August 2018 в 04:24
поделиться
  • 1
    он полагается на sizeof(int) == sizeof(float) (используйте '!' для принудительного 4 байта для формата i). ctypes.sizeof(ctypes.c_int) может зависеть от платформы. Существует int.from_bytes() на Python 3.2+ – jfs 8 May 2013 в 17:11
  • 2
    @ J.F.Sebastian - я полагаю, я также предполагаю, что bin возвращает стандартное представление IEEE ... – mgilson 8 May 2013 в 17:19
  • 3
    нет. Я не понимаю, о чем вы говорите. – jfs 8 May 2013 в 17:25
  • 4
    Полагаю, и я тоже. Функция bin не гарантирует многого о выходе - только то, что это объект, который может обрабатывать python. Если sizeof(int) != sizeof(float), то он не использует IEEE 754 (не так ли?). В этом случае битовая диаграмма, возвращаемая bin, может быть и тем же - например, биты могут быть сообщены в обратном направлении или что-то из-за различной консистенции. Знак бит может быть где-то еще и т. Д. И т. Д. – mgilson 8 May 2013 в 17:29
  • 5
    Проблема sizeof(int) != sizeof(float) не связана с bin() (которая работает с целыми числами Python, которые не ограничены). Для поддержки отрицательных поплавков используйте формат !I . – jfs 8 May 2013 в 17:41

Вы можете использовать .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'
0
ответ дан Robert Hughes 18 August 2018 в 04:24
поделиться

Нашел другое решение, используя модуль bitstring .

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

Выход:

00111111100000000000000000000000
16
ответ дан TheMeaningfulEngineer 18 August 2018 в 04:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: