Python: получить и манипулировать (в виде целых чисел) битовых шаблонов с плавающей точкой - PullRequest
11 голосов
/ 17 декабря 2009

В Python V.2.5.4 у меня есть число с плавающей запятой, и я хотел бы получить и манипулировать (как целое число) битовой комбинацией этого числа с плавающей запятой.

Например, предположим, у меня есть

x = 173.3125

В формате IEEE 754 битовый шаблон x (в шестнадцатеричном формате) равен 432D5000.

Как я могу получить и манипулировать (например, выполнять побитовые операции) с этим битовым шаблоном?

Ответы [ 5 ]

14 голосов
/ 17 декабря 2009

Вы можете получить желаемую строку (очевидно, подразумевающую 32-разрядное представление с прямым порядком байтов; Python внутренне использует собственный порядковый номер и 64-разрядные числа с плавающей точкой) с помощью модуля struct:

>>> import struct
>>> x = 173.125
>>> s = struct.pack('>f', x)
>>> ''.join('%2.2x' % ord(c) for c in s)
'432d2000'

это еще не позволяет вам выполнять побитовые операции, но затем вы можете снова использовать struct для отображения строки в int:

>>> i = struct.unpack('>l', s)[0]
>>> print hex(i)
0x432d2000

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

11 голосов
/ 17 декабря 2009

Проблема в том, что объект с плавающей точкой Python может быть не IEEE 754, потому что это объект (на самом деле это так, но внутренне они могут содержать любое удобное представление) ...

Как сказал Лео, вы можете выполнять приведение типов с помощью ctypes, поэтому вы применяете определенное представление (в данном случае, с одинарной точностью):

from ctypes import *
x = 173.3125
bits = cast(pointer(c_float(x)), POINTER(c_int32)).contents.value
print hex(bits)
#swap the least significant bit
bits ^= 1

А потом обратно:

y = cast(pointer(c_int32(bits)), POINTER(c_float)).contents.value
2 голосов
/ 17 декабря 2009

Используйте struct или xdrlib модуль:

>>> import struct
>>> x = 173.3125
>>> rep = struct.pack('>f', x)
>>> numeric = struct.unpack('>I', rep)[0]
>>> '%x' %numeric
'432d5000'

Теперь вы можете работать с numeric, а затем идти в обратном направлении, чтобы вернуть число с плавающей запятой. Вы должны использовать> I (unsigned int), чтобы избежать получения отрицательного числа. xdrlib похоже.

Ссылки: struct , xdrlib .

1 голос
/ 09 июля 2015

Для справки, также можно использовать numpy и view.

import numpy

def fextract( f ):
  bits = numpy.asarray( f, dtype=numpy.float64 ).view( numpy.int64 )
  if not bits & 0x7fffffffffffffff: # f == +/-0
    return 0, 0
  sign = numpy.sign(bits)
  exponent = ( (bits>>52) & 0x7ff ) - 1075
  mantissa = 0x10000000000000 | ( bits & 0xfffffffffffff )
  # from here on f == sign * mantissa * 2**exponent
  for shift in 32, 16, 8, 4, 2, 1:
    if not mantissa & ((1<<shift)-1):
      mantissa >>= shift
      exponent += shift
  return sign * mantissa, exponent

fextract( 1.5 ) # --> 3, -1
0 голосов
/ 17 декабря 2009

Я не слишком хорошо разбираюсь в этой теме, но вы пробовали модуль ctypes?

...