Положительное целое из функции хеша() 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