Python: создание десятичной запятой с фиксированной точкой из двух 32-битных целых (одна для части int, другая для десятичной) - PullRequest
3 голосов
/ 28 сентября 2010

У меня есть 64-битная временная метка, распакованная из файла с двоичными данными, где старшие 32 бита - это количество секунд, а нижние 32 бита - это доля секунды.Я застрял с тем, как на самом деле преобразовать нижние 32 бита в дробь без циклического прохождения по ней.

Любые предложения?

Для справки, число 4ca1f350 9481ef80 переводитв 1285682000.580107659

Редактировать: Для контекста: данные поступают с устройства захвата пакетов, и в документации, которую я видел, говорится, что дробная часть имеет точность примерно с точностью до наносекунды (в частности, она выводит 29 из 32биты, дающие ~ 2 нс).

Ответы [ 3 ]

3 голосов
/ 28 сентября 2010

Вы можете просто разделить шестнадцатеричное число на максимально возможное, чтобы получить правильное соотношение:

>>> float(0x9481ef80) / 0x100000000
0.58010765910148621
2 голосов
/ 28 сентября 2010

Чтобы представить сумму целой и дробной частей с достаточной точностью (32 + 29 = 61 бит), вам нужно десятичное число (по умолчанию 28 десятичных цифр, что достаточно для 93 бит),

>>> from decimal import Decimal
>>> Decimal(0x9481ef80) / Decimal(2**32) + Decimal(0x4ca1f350)
Decimal('1285682000.580107659101486206')

или дробь (точная),

>>> from fractions import Fraction
>>> Fraction(0x9481ef80, 2**32) + Fraction(0x4ca1f350)
Fraction(43140329262089183, 33554432)
>>> float(_)
1285682000.5801077

Обратите внимание, что число с плавающей запятой использует "двойной формат IEEE", поэтому он может содержать только 53 бита точности:

>>> a = 0x9481ef80 / 2**32 + 0x4ca1f350
>>> b = 0x9481ef90 / 2**32 + 0x4ca1f350
>>> a == b

Хорошо, если вы храните дробную часть как свою собственную переменную, но если это так, то почему бы просто не оставить ее как есть?

>>> 0x9481ef80 / 2**32
0.5801076591014862
>>> 0x9481ef90 / 2**32
0.5801076628267765
1 голос
/ 29 сентября 2010

Вы не сказали секунд с тех пор, как .Похоже, это с 1970-01-01.Вы можете рассчитать коэффициент выдумки, который представляет собой количество секунд между эпохой (1970-01-01) и ожидаемым самым низким значением.Затем вы настраиваете каждое значение ... vadj = float(hi32 - fudge) + lo32 / 2.0 ** 32

Если разница между max (hi32) и min (lo32) составляет менее 6 дней (должно быть достаточно для упражнения по захвату пакета (?))тогда вам нужно только 19 бит для hi32 - выдумка.19 бит + 32 бита - это 51 бит - в пределах точности Python IIRC.

Уже поздно, поэтому я не собираюсь делать подробный анализ, но вышеприведенное должно дать вам картину.

Редактировать: почему ответ @ unwind не работает:

>>> a = 0x00000001/4294967296.0 + 0x4ca1f350
>>> b = 0x00000002/4294967296.0 + 0x4ca1f350
>>> b - a
0.0
>>>

Редактировать 2: Какие операции вы хотите выполнить с отметкой времени, кроме str (), repr (), timestamp_from_str ()?Разница во всем, что приходит на ум.Вы можете использовать что-то вроде этого:

>>> class TS64(object):
...   def __init__(self, hi, lo):
...     self.hi = hi
...     self.lo = lo
...   def float_delta(self, other):
...     hi_delta = self.hi - other.hi
...     # check that abs(hi_delta) is not too large, if you must
...     return hi_delta + (self.lo - other.lo) / 4294967296.0
...
>>> a = TS64(0x4ca1f350, 1)
>>> b = TS64(0x4ca1f350, 2)
>>> b.float_delta(a)
2.3283064365386963e-10
>>> repr(_)
'2.3283064365386963e-10'
>>>

О моем комментарии «если вам нужно»: если наблюдения разделены более чем на 6 дней, вам действительно нужна точность до последнего (секунда / 2 **32) ???ИМХО, если вы делаете float(difference(ts1, ts2)) вместо float(ts1) - float(ts2), вы должны быть в порядке.

Редактировать 3: Предупреждение о неоднозначности / несоответствии

Пожалуйста, измените свой вопрос по адресуследующие проблемы:

Вы говорите в комментарии, что "" "документация, на которую я смотрю, говорит, что она имеет дробную часть с точностью до наносекунды (в частности, она выводит 29 из 32 бит)" "",Пожалуйста, укажите URL для этой документации.

В секунду 1000000000 (10**9) наносекунд.Можно ожидать, что дробная часть потребует math.log(10**9, 2) округленных (то есть 29,897352853986263 округленных, т.е. 30) битов, а не 29. Пожалуйста, объясните.

Пожалуйста, ответьте: из 32 доступных битов, которые содержат 29 или 30 битдробная часть и какие 3 или 2 бита всегда равны нулю?

Во-вторых, можно было бы преобразовать наносекунды в секунды путем деления на 10**9.Однако ваше утверждение в вашем вопросе "" "число 4ca1f350 9481ef80 переводится как 1285682000.580107659" "" соответствует делению на 2**32.На самом деле 0x9481ef80 - это 2 491 543 424, что больше чем вдвое 10**9.Пожалуйста, объясни.Каков источник заявления "переводится в"?У вас есть другие примеры?

...