2

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.

pavel
  • 26,538
  • 10
  • 45
  • 61

2 Answers2

2

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.

user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • From Rob Potter Thanks - looks good for large data arrays (which we'll get to some time after detailed logic design. Random number testing si great fun (when it works). – user3818787 Jul 10 '14 at 08:21
1

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.

jsbueno
  • 99,910
  • 10
  • 151
  • 209
  • Thanks, Looks good. Purpose is design verification for logic design of high performance div, log, exp functions etc. Who loves IEEE 754? – user3818787 Jul 10 '14 at 08:57