web-dev-qa-db-fra.com

Entier positif de la fonction Python hash ()

Je veux utiliser la fonction Python hash() pour obtenir des hachages entiers à partir d'objets. Mais hash() intégré peut donner des valeurs négatives, et je ne veux que du positif. Et je veux que cela fonctionne sensiblement sur les plates-formes 32 bits et 64 bits.

C'est à dire. sur Python 32 bits, hash() peut renvoyer un entier compris entre -2**31 et 2**31 - 1. Sur les systèmes 64 bits, hash() peut renvoyer un entier compris entre -2**63 Et 2**63 - 1.

Mais je veux un hachage dans la plage 0 À 2**32-1 Sur les systèmes 32 bits et 0 À 2**64-1 Sur les systèmes 64 bits.

Quelle est la meilleure façon de convertir la valeur de hachage en sa valeur positive équivalente dans la plage de la plate-forme cible 32 ou 64 bits?

(Contexte: j'essaie de créer une nouvelle classe de style random.Random. Selon les documents random.Random.seed() , l'argument optionnel "x" de départ peut être n'importe quel objet lavable. "Je voudrais donc dupliquer cette fonctionnalité, sauf que mon algorithme de départ ne peut pas gérer des valeurs entières négatives, mais uniquement positives.)

21
Craig McQueen

En utilisant sys.maxsize :

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

Alternative utilisant ctypes.c_size_t :

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

J'utilise simplement sys.maxsize est erroné pour des raisons évidentes (étant `2 * n-1 et non 2 * n), mais la correction est assez simple:

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

pour des raisons de performances, vous souhaiterez peut-être diviser sys.maxsize + 1 en deux affectations distinctes pour éviter de créer temporairement un entier long pour la plupart des nombres négatifs. Bien que je doute que cela compte beaucoup

4
Voo

Que diriez-vous:

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

Cela utilise sys.maxsize pour être portable entre les systèmes 32 et 64 bits.

1
unwind

(Edit: au début, je pensais que vous vouliez toujours une valeur 32 bits)

Simplement ET avec un masque de la taille souhaitée. Généralement sys.maxsize sera déjà un tel masque, car c'est une puissance de 2 moins 1.

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

new_hash = hash & sys.maxsize
1
Mark Ransom