Положительное целое из функции хеша() Python

Я хочу использовать функцию Python hash() для получения целых хэшей из объектов. Но встроенный hash() может давать отрицательные значения, и я хочу только положительный. И я хочу, чтобы он работал разумно на 32-битных и 64-битных платформах.

т.е. на 32-битном Python, hash() может возвращать целое число в диапазоне от -2**31 до 2**31 - 1. В 64-битных системах hash() может возвращать целое число в диапазоне от -2**63 до 2**63 - 1.

Но я хочу хэш в диапазоне от 0 до 2**32-1 в 32-битных системах и 0 до 2**64-1 в 64-битных системах.

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

(Контекст: я пытаюсь создать новый класс стиля random.Random. В соответствии с random.Random.seed() docs семенной "необязательный аргумент x" может быть любой хешируемый объект ". Поэтому я хотел бы дублировать эту функциональность, за исключением того, что мой алгоритм семени не может обрабатывать отрицательные целочисленные значения, только положительные.)

Ответ 1

Использование sys.maxsize:

>>> import sys
>>> sys.maxsize
9223372036854775807L
>>> hash('asdf')
-618826466
>>> hash('asdf') % ((sys.maxsize + 1) * 2)
18446744073090725150L

Альтернативный вариант ctypes.c_size_t:

>>> import ctypes
>>> ctypes.c_size_t(hash('asdf')).value
18446744073090725150L

Ответ 2

Просто использование sys.maxsize неверно по понятным причинам (это `2 * n-1, а не 2 * n), но исправление достаточно просто:

h = hash(obj)
h += sys.maxsize + 1

по соображениям производительности вам может понадобиться разделить sys.maxsize + 1 на два отдельных назначения, чтобы избежать долгого целого числа для большинства отрицательных чисел. Хотя я сомневаюсь, что это будет иметь большое значение.

Ответ 3

Как насчет:

h = hash(o)
if h < 0:
  h += sys.maxsize

Используется sys.maxsize для переносимости между 32- и 64-разрядными системами.

Ответ 4

(Edit: сначала я думал, что вам всегда нужно 32-битное значение)

Просто И это с маской желаемого размера. Обычно sys.maxsize уже будет такой маской, так как она имеет мощность 2 минус 1.

import sys
assert (sys.maxsize & (sys.maxsize+1)) == 0 # checks that maxsize+1 is a power of 2 

new_hash = hash & sys.maxsize