Поплавок в двоичный - PullRequest
       6

Поплавок в двоичный

6 голосов
/ 29 января 2011

Я пытаюсь преобразовать число с плавающей запятой в двоичное представление; как я могу этого достичь? Однако моя цель - не ограничиваться 2 м, поэтому я надеюсь на то, что можно легко распространить на любой базовый (3, 4, 8) экв.

У меня есть простая реализация целых чисел:

import string

LETTER = '0123456789' + string.ascii_lowercase
def convert_int(num, base):
    if base == 1:
        print "WARNING! ASKING FOR BASE = 1"
        return '1' * num if num != 0 else '0'

    if base > 36: raise ValueError('base must be >= 1 and <= 36')

    num, rest = divmod(num, base)
    rest = [LETTER[rest]]
    while num >= base:
        num, r = divmod(num, base)
        rest.append(LETTER[r])
    rest.reverse()
    return (LETTER[num] if num else '') + ''.join(str(x) for x in rest)

любая помощь приветствуется:)

редактирование:

def convert_float(num, base, digits=None):
    num = float(num)
    if digits is None: digits = 6

    num = int(round(num * pow(base, digits)))
    num = convert_int(num, base)
    num = num[:-digits] + '.' + num[:digits]
    if num.startswith('.'): num = '0' + num
    return num

это верно? почему я получаю такое поведение?

>>> convert_float(1289.2893, 16)
'509.5094a0'
>>> float.hex(1289.2983)
'0x1.42531758e2196p+10'

p.s. Как преобразовать число с плавающей запятой в двоичный?

Я читал эту дискуссию, но я не получил ответа ... Я имею в виду, она работает только для 0,25, 0,125? и я не понимаю фразу «должно быть в обратном порядке» ...

Ответы [ 6 ]

16 голосов
/ 29 января 2011

Для поплавков есть встроенный метод hex ().

http://docs.python.org/library/stdtypes.html#float.hex

Это дает вам шестнадцатеричное представление данного числа. И перевод с шестнадцатеричного на двоичный формат тривиален.

Например:

In [15]: float.hex(1.25)
Out[15]: '0x1.4000000000000p+0'

In [16]: float.hex(8.25)
Out[16]: '0x1.0800000000000p+3'
12 голосов
/ 30 января 2011

Следующий ответ с небольшим количеством теории.

Объяснение ниже не объясняет стандарт IEEE с плавающей запятой, только общие идеи относительно представления чисел с плавающей запятой

Каждое число с плавающей точкой представлено дробной частью, умноженной на показатель степени, умноженный на знак. Кроме того, существует так называемое смещение для показателя степени, которое будет объяснено ниже.

Итак, мы имеем

  1. Знаковый бит
  2. Цифры дробной части
  3. цифры экспонентной части

Пример для базы 2 с 8-битной дробью и 8-битным показателем

Биты в дробной части сообщают нам, какие слагаемые (числа, которые нужно добавить) из последовательности ниже должны быть включены в представленное значение числа

2 ^ -1 + 2 ^ -2 + 2 ^ -3 + 2 ^ -4 + 2 ^ -5 + 2 ^ -6 + 2 ^ -7 + 2 ^ -8

Итак, если вы скажете 01101101 в дробной части, это даст

0 * 2 ^ -1 + 1 * 2 ^ -2 + 1 * 2 ^ -3 + 0 * 2 ^ -4 + 1 * 2 ^ -5 + 1 * 2 ^ -6 + 0 * 2 ^ - 7 + 1 * 2 ^ -8 = 0,42578125

Теперь ненулевые числа, которые представляются таким образом, попадают между 2 ** -8 = 0,00390625 и 1 - 2 ** - 8 = 0,99609375

Здесь начинается экспоненциальная часть. Экспонента позволяет нам представлять очень большие числа, умножая дробную часть на экспоненту. Поэтому, если у нас есть 8-битный показатель, мы можем умножить полученную дробь на числа между 0 и 2 ^ 255.

Итак, возвращаясь к примеру выше, возьмем показатель степени 11000011 = 195.

У нас есть дробная часть 01101101 = 0,42578125 и экспонента 11000011 = 195. Это дает нам число 0,42578125 * 2 ^ 195, это действительно большое число.

Пока что мы можем представлять ненулевые числа между 2 ^ -8 * 2 ^ 0 и (1-2 ^ -8) * 2 ^ 255. Это учитывает очень большие числа, но не очень маленькие числа. Чтобы иметь возможность представлять малые числа, мы должны включить в наш показатель степени так называемое смещение. Это число, которое всегда будет вычитаться из показателя степени, чтобы можно было представить маленькие числа.

Давайте возьмем смещение 127. Теперь все показатели вычтены 127. Значения, которые могут быть представлены, находятся между 2 ^ -8 * 2 ^ (0 - 127) и (1-2 ^ -8) * 2 ^ ( 255 - 127 = 128)

Номер примера теперь составляет 0,42578125 * 2 ^ (195-127 = 68), что все еще довольно велико.

Пример заканчивается

Чтобы понять это лучше, попробуйте поэкспериментировать с различными основаниями и размерами для дробной и экспоненциальной части. В начале не пытайтесь использовать нечетные основы, потому что это только усложняет необходимые вещи.

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

8 голосов
/ 29 января 2011

Если вы хотите преобразовать float в строку с d цифрами после десятичной точки :

  1. Умножьте число на base**d.
  2. Округление до ближайшего целого числа.
  3. Преобразовать целое число в строку.
  4. Вставьте символ . d до конца.

Например, для представления 0,1 в базе 12 с 4 десятичными десятками мест,

  1. 0,1 & раз; 12 4 = 2073,6
  2. Округление до ближайшего целого числа & rarr; 2074
  3. Преобразовать в строку & rarr; 124A
  4. Добавить основную точку & rarr; 0.124A
1 голос
/ 12 ноября 2018

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

s = "1101.0101"
s1, s2 = s.split(".")
s1 = int(s1, 2)
s2 = int(s2, 2)/(2**len(s2))
x = s1+s2
print(x)

Вывод:

13.3125

Надеюсь, он кому-нибудь пригодится.

1 голос
/ 10 декабря 2012

Это не тот стиль двоичного представления, который вам нужен, но он преобразует IEEE 754 в его знак, мантиссу и основание, которые можно использовать для создания шестнадцатеричного представления довольно простым способом.Обратите внимание, что «значение» мантиссы равно 1 + BINARY, где BINARY - это двоичное представление - следовательно, в возвращаемом значении -1.

Я написал этот код и объявил его общедоступным.1004 *

0 голосов
/ 07 сентября 2016

Отвечая непосредственно на заголовок и используя float.hex, который использует 64-битный IEE754, можно написать этот метод:

def float_to_bin(x):
  if x == 0:
    return "0" * 64
  w, sign = (float.hex(x), 0) if x > 0 else (float.hex(x)[1:], 1)
  mantissa, exp = int(w[4:17], 16), int(w[18:])
  return "{}{:011b}{:052b}".format(sign, exp + 1023, mantissa)

float_to_bin(-0.001) # '1011111101010000000010110011111101011000011011100110110100101010'

Обратите внимание, что это не работает для NaN и Inf.

...