tags:

views:

165

answers:

4

In Python V.2.5.4, I have a float, and I'd like to obtain and manipulate (as an integer) the bit pattern of that float.

For example, suppose I have

x = 173.3125

In IEEE 754 format, x's bit pattern (in hexadecimal) is 432D5000 .

How can I obtain & manipulate (e.g., perform bitwise operations) on that bit pattern?

+1  A: 

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

leo-the-manic
+3  A: 

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 *
bits = cast(pointer(c_float(173.3125)), POINTER(c_int32)).contents.value
print hex(bits)
fortran
+5  A: 

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).

Alex Martelli
JaysonFix
Also, I was wondering whether there are significant performance differences between the "ctypes" and "struct" solutions.
JaysonFix
@JaysonFix: 1) do you mean platform-independent? If so, and you are explicit about endianism, I think the answer is yes. 2) Whether there is enough difference to matter to you depends on what you're going to be doing... millions of manipulations? If so, you should benchmark for yourself so you'll understand the implications, both in terms of performance in in terms of ease of use and maintainability.
Peter Hansen
+1  A: 

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. xdrlib is similar.

References: struct, xdrlib.

Alok