Selon la documentation Java, le code de hachage d'un String
objet est calculé comme suit:
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
en utilisant l'
int
arithmétique, oùs[i]
est le i ème caractère de la chaîne,n
est la longueur de la chaîne, et^
indique l'exponentiation.
Pourquoi 31 est-il utilisé comme multiplicateur?
Je comprends que le multiplicateur doit être un nombre premier relativement grand. Alors pourquoi pas 29, 37, voire 97?
Réponses:
Selon Effective Java de Joshua Bloch (un livre qui ne peut pas être assez recommandé, et que j'ai acheté grâce aux mentions continuelles sur stackoverflow):
(extrait du chapitre 3, élément 9: toujours remplacer le code de hachage lorsque vous remplacez égal, page 48)
la source
Comme le soulignent Goodrich et Tamassia , si vous prenez plus de 50 000 mots anglais (formés comme l'union des listes de mots fournies dans deux variantes d'Unix), l'utilisation des constantes 31, 33, 37, 39 et 41 produira moins de 7 collisions dans chaque cas. Sachant cela, il n'est pas surprenant que de nombreuses implémentations Java choisissent l'une de ces constantes.
Par coïncidence, j'étais en train de lire la section "codes de hachage polynomiaux" quand j'ai vu cette question.
EDIT: voici le lien vers le livre PDF ~ 10 Mo auquel je fais référence ci-dessus. See section 10.2 Hash Tables (page 413) de Data Structures and Algorithms in Java
la source
Sur (principalement) d'anciens processeurs, la multiplication par 31 peut être relativement bon marché. Sur un ARM, par exemple, ce n'est qu'une instruction:
La plupart des autres processeurs nécessiteraient une instruction de décalage et de soustraction distincte. Cependant, si votre multiplicateur est lent, c'est toujours une victoire. Les processeurs modernes ont tendance à avoir des multiplicateurs rapides, donc cela ne fait pas beaucoup de différence, tant que 32 va du bon côté.
Ce n'est pas un excellent algorithme de hachage, mais il est suffisamment bon et meilleur que le code 1.0 (et bien meilleur que la spécification 1.0!).
la source
String.hashCode
est antérieur au StrongARM qui, IIRC, a introduit un multiplicateur à 8 bits et peut-être augmenté à deux cycles pour l'arithmétique / logique combinée avec des opérations de décalage.Map.Entry
a été corrigé par spécification pour êtrekey.hashCode() ^ value.hashCode()
malgré qu'il ne soit même pas une paire non ordonnée,key
etvalue
a une signification entièrement différente. Oui, cela implique queMap.of(42, 42).hashCode()
ouMap.of("foo", "foo", "bar", "bar").hashCode()
, etc., sont vraisemblablement nuls. Alors n'utilisez pas les cartes comme clés pour d'autres cartes…En multipliant, les bits sont décalés vers la gauche. Cela utilise davantage d'espace disponible de codes de hachage, ce qui réduit les collisions.
En n'utilisant pas une puissance de deux, les bits de poids faible de droite sont également remplis, pour être mélangés avec la prochaine donnée entrant dans le hachage.
L'expression
n * 31
est équivalente à(n << 5) - n
.la source
Vous pouvez lire le raisonnement original de Bloch sous "Commentaires" dans http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4045622 . Il a étudié les performances de différentes fonctions de hachage en ce qui concerne la "taille de chaîne moyenne" résultante dans une table de hachage.
P(31)
était l'une des fonctions communes à cette époque qu'il a trouvées dans le livre de K&R (mais même Kernighan et Ritchie ne pouvaient pas se rappeler d'où cela venait). En fin de compte, il a dû en choisir un et il l'a donc prisP(31)
car il semblait fonctionner assez bien. Même si ceP(33)
n'était pas vraiment pire et que la multiplication par 33 est également rapide à calculer (juste un décalage de 5 et un ajout), il a opté pour 31 car 33 n'est pas un nombre premier:Le raisonnement n'était donc pas aussi rationnel que la plupart des réponses semblent le laisser entendre. Mais nous sommes tous bons pour trouver des raisons rationnelles après des décisions intestinales (et même Bloch pourrait être enclin à cela).
la source
En fait, 37 fonctionnerait plutôt bien! z: = 37 * x peut être calculé comme
y := x + 8 * x; z := x + 4 * y
. Les deux étapes correspondent à une instruction LEA x86, c'est donc extrêmement rapide.En fait, la multiplication avec le premier 73 encore plus grand pourrait être effectuée à la même vitesse en réglant
y := x + 8 * x; z := x + 8 * y
.Utiliser 73 ou 37 (au lieu de 31) pourrait être mieux, car cela conduit à un code plus dense : les deux instructions LEA ne prennent que 6 octets contre les 7 octets pour déplacer + déplacer + soustraire pour la multiplication par 31. Une mise en garde possible est que les instructions LEA à 3 arguments utilisées ici sont devenues plus lentes sur l'architecture du pont Sandy d'Intel, avec une latence accrue de 3 cycles.
De plus, 73 est le numéro préféré de Sheldon Cooper.
la source
Neil Coffey explique pourquoi 31 est utilisé sous Aplanir le biais .
Fondamentalement, l'utilisation de 31 vous donne une distribution de probabilité de bit de jeu plus uniforme pour la fonction de hachage.
la source
Extrait de JDK-4045622 , où Joshua Bloch décrit les raisons pour lesquelles cette (nouvelle)
String.hashCode()
mise en œuvre particulière a été choisiela source
Bloch n'entre pas tout à fait dans cela, mais la raison pour laquelle j'ai toujours entendu / cru est que c'est l'algèbre de base. Les hachages se résument aux opérations de multiplication et de module, ce qui signifie que vous ne voudrez jamais utiliser des nombres avec des facteurs communs si vous pouvez l'aider. En d'autres termes, les nombres relativement premiers fournissent une distribution uniforme des réponses.
Les nombres qui composent en utilisant un hachage sont généralement:
Vous ne pouvez vraiment contrôler que quelques-unes de ces valeurs, donc un peu de soin supplémentaire est dû.
la source
Dans la dernière version de JDK, 31 est toujours utilisé. https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/lang/String.html#hashCode ()
Le but de la chaîne de hachage est
^
dans le document de calcul du code de hachage, cela aide à unique)31 est la valeur maximale peut être mise dans un registre de 8 bits (= 1 octet), est le plus grand nombre premier peut être mis dans un registre de 1 octet, est un nombre impair.
Multiplier 31 est << 5 puis se soustraire, donc besoin de ressources bon marché.
la source
Je ne suis pas sûr, mais je suppose qu'ils ont testé un échantillon de nombres premiers et ont constaté que 31 donnait la meilleure distribution sur un échantillon de chaînes possibles.
la source
C'est parce que 31 a une belle propriété - sa multiplication peut être remplacée par un décalage au niveau du bit qui est plus rapide que la multiplication standard:
la source