Получить и манипулировать битовым шаблоном с плавающей точкой как целое число

В Python 2.5 у меня есть число с плавающей точкой, и я хотел бы получить и управлять его битовым шаблоном в виде целого числа.

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

x = 173.3125

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

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

Ответ 1

Вы можете получить нужную вам строку (видимо, подразумевая 32-битное представление в формате big-endian, Python внутренне использует встроенную endianity и 64-бит для float) с модулем 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).

Ответ 2

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

Как сказал лев, вы можете сделать тип cast с 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

Ответ 3

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

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

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

Ссылки: struct, xdrlib.

Ответ 4

Для справки также можно использовать 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

Ответ 5

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