Reputation: 14041
I want to convert a float (the output of time.time()
) in hex using python 2.4/2.5.
I found tons of examples that convert hex to float, but I cannot find anything that allows me to do what the float.hex()
of python >= 2.6 does.
Upvotes: 1
Views: 4855
Reputation: 172249
Of course it can be done in a portable way, it's just maths. Here's how (inclusing tests proving it works).
from __future__ import division
MAXHEXADECIMALS = 10
def float2hex(f):
w = f // 1
d = f % 1
# Do the whole:
if w == 0:
result = '0'
else:
result = ''
while w:
w, r = divmod(w, 16)
r = int(r)
if r > 9:
r = chr(r+55)
else:
r = str(r)
result = r + result
# And now the part:
if d == 0:
return result
result += '.'
count = 0
while d:
d = d * 16
w, d = divmod(d, 1)
w = int(w)
if w > 9:
w = chr(w+55)
else:
w = str(w)
result += w
count += 1
if count > MAXHEXADECIMALS:
break
return result
import unittest
class Float2HexTest(unittest.TestCase):
def test_ints(self):
assert float2hex(0x25) == '25'
assert float2hex(0xFE) == 'FE'
assert float2hex(0x00) == '0'
assert float2hex(0x01) == '1'
assert float2hex(0x14E7F400A5) == '14E7F400A5'
def test_floats(self):
assert float2hex(1/2) == '0.8'
assert float2hex(1/13) == '0.13B13B13B13'
assert float2hex(1034.03125) == '40A.08'
suite = unittest.makeSuite(Float2HexTest)
runner = unittest.TextTestRunner()
runner.run(suite)
Yeah, that's pretty pointless. :-) Of course, the correct answer in this case is to not convert a float to hex, but to use an INTEGER representation of time and convert that to a hex string. But still, it can be done. :)
Upvotes: 1
Reputation: 82934
It can't be done portably in Python before version 2.6; it needs the information in sys.float_info, which is new in Python 2.6.
If you want to do it non-portably, i.e. for your particular platform, you would need to look at the float.h
file for the C compiler that was used to produce your 2.4/5 Python, or at the sys.float_info returned by a 2.6 or 2.7 implementation on your platform (and trust that it applies to your 2.4/5 Python). Then you would need to look at the float_hex
function in the Python source (Objects/floatobject.c) and translate that to Python and test it (against a 2.6/7 Python, perhaps).
This seems like a lot of work, for what? What is your goal? What do you want to do that can't be achieved with repr(your_float)
?
Edit: need for a unique identifier
Note that time.time() is not very precise:
""" time.time() Return the time as a floating point number expressed in seconds since the epoch, in UTC. Note that even though the time is always returned as a floating point number, not all systems provide time with a better precision than 1 second. While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back between the two calls. """
Allowing for up to a billionth of a second resolution:
>>> hex(int(time.time() * 1000000000))
'0x11ef11c41cf98b00L'
>>>
Is that good enough?
Upvotes: 3
Reputation: 304195
Here is the C version of the code, I don't have time to port it right now, but maybe someone else can.
float_hex(PyObject *v)
{
double x, m;
int e, shift, i, si, esign;
/* Space for 1+(TOHEX_NBITS-1)/4 digits, a decimal point, and the
trailing NUL byte. */
char s[(TOHEX_NBITS-1)/4+3];
CONVERT_TO_DOUBLE(v, x);
if (Py_IS_NAN(x) || Py_IS_INFINITY(x))
return float_str((PyFloatObject *)v);
if (x == 0.0) {
if (copysign(1.0, x) == -1.0)
return PyString_FromString("-0x0.0p+0");
else
return PyString_FromString("0x0.0p+0");
}
m = frexp(fabs(x), &e);
shift = 1 - MAX(DBL_MIN_EXP - e, 0);
m = ldexp(m, shift);
e -= shift;
si = 0;
s[si] = char_from_hex((int)m);
si++;
m -= (int)m;
s[si] = '.';
si++;
for (i=0; i < (TOHEX_NBITS-1)/4; i++) {
m *= 16.0;
s[si] = char_from_hex((int)m);
si++;
m -= (int)m;
}
s[si] = '\0';
if (e < 0) {
esign = (int)'-';
e = -e;
}
else
esign = (int)'+';
if (x < 0.0)
return PyString_FromFormat("-0x%sp%c%d", s, esign, e);
else
return PyString_FromFormat("0x%sp%c%d", s, esign, e);
}
Upvotes: 1