2016-09-20 6 views
2

Я пытаюсь преобразовать данные типа double с длиной 64 бит в десятичное значение. Я следую https://en.wikipedia.org/wiki/Double-precision_floating-point_format для преобразования.Двойное преобразование в десятичное значение IEEE-754 в Python

Я попробовал его в следующий сценарий:

a = '\x3f\xd5\x55\x55\x55\x55\x55\x55' # Hexbyte representation of 1/3 value in double 

sign_bit = bin(ord(a[0])).replace('0b', '').rjust(8, '0')[0] 
sign = -1 ** int(sign_bit) 
print sign # Sign bit 

# Next 11 bits for exponent calculation 
exp_bias = 1023 
a11 = bin(ord(a[0])).replace('0b', '').rjust(8, '0')[1:] + bin(ord(a[1])).replace('0b', '').rjust(8, '0')[:4] 
exp = int(a11, 2) 
print exp 

# Next 52 bits for fraction calculation 
fraction = bin(ord(a[1])).replace('0b', '').rjust(8, '0')[4:] + bin(ord(a[2])).replace('0b', '').rjust(8, '0') \ 
      + bin(ord(a[3])).replace('0b', '').rjust(8, '0') + bin(ord(a[4])).replace('0b', '').rjust(8, '0') \ 
      + bin(ord(a[5])).replace('0b', '').rjust(8, '0') + bin(ord(a[6])).replace('0b', '').rjust(8, '0') \ 
      + bin(ord(a[7])).replace('0b', '').rjust(8, '0') 
print len(fraction), fraction 
fract = str(int(fraction, 2)) 
print len(fract), fract 
fin = repr(float(fract)/ 10 ** 16) 
print type(fin), fin # 16 digit precision 

# final value calculation according equation 
# eq = (-1)^sign * 2 ^(exp- exp_bias) * (1 + fin) 
val = 2 ** (exp - exp_bias) * float(fin) # Looses precision 
print val 

Пожалуйста, любой один помочь мне с этим. Я не могу понять, где я ошибаюсь? Причина. Я могу иметь значение фракции с точностью, используя repr(), но всякий раз, когда вы пытаетесь использовать ее в уравнение, она теряет свою точность в float().

Есть ли способ или альтернативный способ его решения?

+3

Ваш код может быть намного проще, если вы используете [ByteArray] (https://docs.python.org/2.7/library/functions.html#bytearray) – janbrohl

+0

Если возможно, не работают со строками до тех пор, возможно, но с целыми числами. Например, 'sign_bit = bytearray (a) [0] >> 7. Также, если возможно, не используйте float, поскольку вы теряете точность для большинства операций с плавающей запятой. – janbrohl

+0

@janbrohl Благодарим за предложение. – abhi1610

ответ

3

Простой способ сделать это преобразование - использовать модуль struct.

from struct import unpack 

a = '\x3f\xd5\x55\x55\x55\x55\x55\x55' 
n = unpack('>d', a) 
print '%.18f' % n[0] 

выход

0.33333333333333331 

В Python 3, необходимо указать строку ввода и строку формата упаковки в виде байтовых строк, например

a = b'\x3f\xd5\x55\x55\x55\x55\x55\x55' 
n = unpack(b'>d', a) 
print(format(n[0], '.18f')) 

Вы можете также использовать b префикс строки в Python 2 (от 2.6 и выше, IIRC). Python 2 просто игнорирует этот префикс, поскольку обычные строки Python 2 представляют собой байтовые строки.

+0

Спасибо. Мне глупо, чтобы не думать об этом. Но, если я хочу использовать этот 'n' в некотором расчете, чем то, что можно сделать? – abhi1610

+1

@ abhi1610 Функция 'struct.unpack' возвращает кортеж, так как его можно использовать для распаковки нескольких элементов данных из строки. Вот почему я использовал 'n [0]' для доступа к значению объекта 'float'. Python 'float' являются стандартными [64-битная двоичная версия IEEE-754 с двойной точностью] (https: //en.wikipedia.org/wiki/Double-precision_floating-point_format # IEEE_754_double-precision_binary_floating-point_format: _binary64). –

2

Слишком много работы.

>>> import struct 
>>> struct.unpack('>d', '\x3f\xd5\x55\x55\x55\x55\x55\x55')[0] 
0.3333333333333333 

 Смежные вопросы

  • Нет связанных вопросов^_^