Obtain & manipulate bit pattern of float as integer

前端 未结 5 1778
抹茶落季
抹茶落季 2020-12-09 19:05

In Python 2.5, I have a float and I\'d like to obtain and manipulate its bit pattern as an integer.

For example, suppose I have

x = 173.3125
<         


        
相关标签:
5条回答
  • 2020-12-09 19:30

    Use struct or xdrlib module:

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

    Now you can work with numeric, and then go in the reverse direction to get your floating point number back. You have to use >I (unsigned int) to avoid getting a negative number. xdrlib is similar.

    References: struct, xdrlib.

    0 讨论(0)
  • 2020-12-09 19:32

    For reference, it is also possible to use numpy and 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 讨论(0)
  • 2020-12-09 19:35

    You can get the string you want (apparently implying a big-endian, 32-bit representation; Python internally uses the native endianity and 64-bits for floats) with the struct module:

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

    this doesn't yet let you perform bitwise operations, but you can then use struct again to map the string into an int:

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

    and now you have an int which you can use in any sort of bitwise operations (follow the same two steps in reverse if after said operations you need to get a float again).

    0 讨论(0)
  • 2020-12-09 19:35

    The problem is that a Python float object might not be a IEEE 754, because it is an object (in fact they are, but internally they could hold whichever representation is more convenient)...

    As leo said, you can do a type cast with ctypes, so you are enforcing a particular representation (in this case, single precision):

    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
    

    And then back:

    y = cast(pointer(c_int32(bits)), POINTER(c_float)).contents.value
    
    0 讨论(0)
  • 2020-12-09 19:40

    I am not too well versed on this topic, but have you tried the ctypes module?

    0 讨论(0)
提交回复
热议问题