Объедините два 32-битных целых числа, чтобы получить 64-битную длину в Python

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

Одна из идей состоит в том, чтобы объединить идентификатор пользователя, который представляет собой 32-битное целое число, с отметкой времени Unix, которая является еще одним 32-битным целым числом, чтобы сформировать уникальное целое число длиной 64 бита.

Пример в уменьшенном масштабе:

Объедините два 4-битных числа 0010 и 0101, чтобы сформировать 8-битное число 00100101.

  1. Есть ли смысл в этой схеме?
  2. Если это так, как мне сделать «конкатенацию» чисел в Python?

person Continuation    schedule 24.08.2010    source источник
comment
Вот связанный вопрос и ответ, когда битовая длина двух входных чисел может не совпадать или когда только один из двух битовых длин известна.   -  person Acumenus    schedule 13.01.2019


Ответы (4)


Сдвиньте первое число влево на количество битов во втором числе, затем добавьте (или побитовое ИЛИ — замените + на | в следующих примерах) второе число.

result = (user_id << 32) + timestamp

Что касается вашего уменьшенного примера,

>>> x = 0b0010
>>> y = 0b0101
>>> (x << 4) + y
37
>>> 0b00100101
37
>>>
person sykora    schedule 24.08.2010
comment
Не могли бы вы использовать | вместо + в этом примере? - person Grant Paul; 24.08.2010
comment
Было бы разумно использовать битовую маску, если какое-либо из значений когда-либо >32 бита. - person Moberg; 15.03.2016
comment
assert y < 0xFFFFFFFF или y &= 0xFFFFFFFF в зависимости от того, разрешены ли большие числа или нет. - person Moberg; 11.01.2019

Это должно сделать это:

(x << 32) + y
person carl    schedule 24.08.2010

Для следующего парня (которым в данном случае был я). Вот один из способов сделать это в целом (для уменьшенного примера):

def combineBytes(*args):
    """
    given the bytes of a multi byte number combine into one
    pass them in least to most significant 
    """
    ans = 0
    for i, val in enumerate(args):
        ans += (val << i*4)
    return ans

для других размеров измените 4 на 32 или что-то еще.

>>> bin(combineBytes(0b0101, 0b0010))
'0b100101'
person Brian Larsen    schedule 18.12.2012

Ни один из ответов до этого не охватывает как слияние, так и разделение чисел. Разделение может быть такой же необходимостью, как и слияние.

NUM_BITS_PER_INT = 4  # Replace with 32, 48, 64, etc. as needed.
MAXINT = (1 << NUM_BITS_PER_INT) - 1

def merge(a, b):
    c = (a << NUM_BITS_PER_INT) | b
    return c

def split(c):
    a = (c >> NUM_BITS_PER_INT) & MAXINT
    b = c & MAXINT
    return a, b

# Test
EXPECTED_MAX_NUM_BITS = NUM_BITS_PER_INT * 2
for a in range(MAXINT + 1):
    for b in range(MAXINT + 1):
        c = merge(a, b)
        assert c.bit_length() <= EXPECTED_MAX_NUM_BITS
        assert (a, b) == split(c)
person Acumenus    schedule 11.01.2019