Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copying internal formats float64 uint64

I'm using Numpy and Python. I need to copy data, WITHOUT numeric conversion between np.uint64 and np.float64, e.g. 1.5 <-> 0x3ff8000000000000.

I'm aware of float.hex, but the output format a long way from uint64:

In [30]: a=1.5
In [31]: float.hex(a)
Out[31]: '0x1.8000000000000p+0'

Im also aware of various string input routines for the other way.

Can anybody suggest more direct methods? After all, its just simple copy and type change but python/numpy seem really rigid about converting the data on the way.

like image 313
user3818787 Avatar asked Feb 06 '26 01:02

user3818787


2 Answers

Use an intermediate array and the frombuffer method to "cast" one array type into the other:

>>> v = 1.5
>>> fa = np.array([v], dtype='float64')
>>> ua = np.frombuffer(fa, dtype='uint64')
>>> ua[0]
4609434218613702656      # 0x3ff8000000000000

Since frombuffer creates a view into the original buffer, this is efficient even for reinterpreting data in large arrays.

like image 54
user4815162342 Avatar answered Feb 09 '26 12:02

user4815162342


So, what you need is to see the 8 bytes that represent the float64 in memory as an integer number. (representing this int64 number as an hexadecimal string is another thing - it is just its representation).

The Struct and Union functionality that comes bundled with the stdlib's ctypes may be nice for you - no need for numpy. It has a Union type that works quite like C language unions, and allow you to do this:

>>> import ctypes
>>> class Conv(ctypes.Union):
...   _fields_ = [ ("float", ctypes.c_double), ("int", ctypes.c_uint64)]
... 
>>> c = Conv()
>>> c.float = 1.5
>>> print hex(c.int)
0x3ff8000000000000L

The built-in "hex" function is a way to get the hexadecimal representation of the number.

You can use the struct module as well: pack the number to a string as a double, and unpack it as int. I think it is both less readable and less efficient than using ctypes Union:

>>> inport struct
>>> hex(struct.unpack("<Q",  struct.pack("<d", 1.5))[0])
'0x3ff8000000000000'

Since you are using numpy , however, you can simply change the array type, "on the fly", and manipulate all the array as integers with 0 copy:

>>> import numpy
>>> x = numpy.array((1.5,), dtype=numpy.double)
>>> x[0]
1.5
>>> x.dtype=numpy.dtype("uint64")
>>> x[0]
4609434218613702656
>>> hex(x[0])
'0x3ff8000000000000L'

This is by far the most efficient way of doing it, whatever is your purpose in getting the raw bytes of the float64 numbers.

like image 29
jsbueno Avatar answered Feb 09 '26 11:02

jsbueno