web-dev-qa-db-fra.com

D'où viennent les constantes de hachage "magiques" comme 0x9e3779b9 et 0x9e3779b1?

Dans le code traitant des tables de hachage, je trouve souvent la constante 0x9e3779b9 ou parfois 0x9e3779b1. Par exemple

hash = n * 0x9e3779b1 >>> 24

Pourquoi cette valeur particulière est-elle utilisée?

137
bkgs

0x9e3779b9 est la partie intégrante de la partie fractionnaire du ratio d'or 0,61803398875… (sqrt (5) -1)/2, multipliée par 2 ^ 32.

Par conséquent, si φ = (sqrt (5) +1)/2 = 1,61803398875 est le nombre d'or, la fonction de hachage calcule la partie fractionnaire de n * φ, qui a de bonnes propriétés de diffusion. Pour vous convaincre, créez simplement un nuage de points de (n, n*c-FLOOR(n*c)) dans votre feuille de calcul préférée, en remplaçant c par φ, e, π, etc. Certains problèmes concrets intéressants lors d'une erreur sont décrits dans https://lkml.org/lkml/ 2016/4/29/838 .

Cette méthode est souvent appelée "Golden Ratio Hashing" ou "Fibonacci Hashing" et a été popularisée par Donald Knuth (The Art of Computer Programming: Volume 3: Sorting and Searching). En termes théoriques numériques, cela se résume principalement à la conjecture de Steinhaus ( https://en.wikipedia.org/wiki/Three-gap_theorem ) et à la symétrie récursive des parties fractionnaires des multiples des multiples de la Nombre d'or φ.

Parfois, vous pouvez également voir 0x9e3779b1, qui est le nombre premier le plus proche de 0x9e3779b9 (et semble être un peu "culte du fret" car ce n'est pas un hachage modulaire). De même, 0x9e3779b97f4a7c15 et 0x9e3779b97f4a7c55 sont les équivalents 64 bits de ces nombres.

220
32f

Les autres réponses expliquent l'intention derrière ces nombres magiques, ce qui est probablement ce que vous vouliez savoir. Cependant, on pourrait dire que "d'où ils viennent" vient de mauvaises pratiques de programmation. Les nombres magiques sont mauvais et ne doivent jamais être utilisés. Les constantes telles que celles mentionnées doivent recevoir des noms de variable descriptive appropriés, et peut-être même des commentaires devraient-ils être ajoutés là où ils sont définis. Ensuite, chaque apparence des valeurs dans le code doit être sous la forme de la variable nommée. Si tel était le cas dans les codes où vous avez rencontré ces valeurs, vous n'auriez pas été préplexé par leur intention en premier lieu.

exemple:

Mauvais exemple - utilise nombres magiques

hash = n * 0x9e3779b1

Meilleur exemple - avec des commentaires et une variable significative

# Golden Ratio constant used for better hash scattering
# See https://softwareengineering.stackexchange.com/a/402543 
GOLDEN_RATIO = 0x9e3779b1
hash = n * GOLDEN_RATIO
30
isilanes
Dans le code traitant des tables de hachage, je trouve souvent la constante 0x9e3779b9 ou parfois 0x9e3779b1

L'autre réponse a expliqué correctement pourquoi cette valeur est utilisée. Cependant, si vous trouvez souvent cette constante, ce que vous ne réalisez peut-être pas, c'est que le code est souvent vulnérable aux attaques par inondation de hachage.

Il existe deux stratégies contre les attaques par inondation de hachage:

  1. Utilisez une fonction de hachage sécurisée ayant une graine aléatoire secrète. Votre fonction de hachage n'a pas de graine aléatoire secrète. Murmurhash3_32 a une graine aléatoire secrète, mais elle a des multicollisions indépendantes de la graine en raison du petit état interne. La meilleure fonction de hachage ayant une sécurité cryptographique proche et des performances encore presque acceptables est probablement SipHash. Malheureusement, il est lent, mais pas aussi lent que SHA512, etc.

  2. Utilisez une fonction de hachage qui est rapide à calculer (comme la fonction de hachage que vous avez trouvée ou Murmurhash3_32) et transformez chaque compartiment de hachage en racine d'un arbre de recherche binaire équilibré. Ainsi, une table de hachage ordinaire chaînée séparément a chaque compartiment comme une liste liée, ce qui est lent si beaucoup de valeurs sont hachées dans le même compartiment. En en faisant un arbre de recherche binaire équilibré tel que l'arbre AVL ou l'arbre rouge-noir, vous avez toujours des performances garanties dans le pire des cas.

Mon avis est que (2) est meilleur parce que SipHash est si lent. De plus, dans l'espace du noyau du système d'exploitation, il peut ne pas y avoir suffisamment d'entropie pour créer une graine aléatoire secrète au début de la phase de démarrage, de sorte que dans l'espace du noyau, vous ne pourrez peut-être pas créer des nombres aléatoires au début du démarrage.

Les tables de hachage sont largement utilisées à mauvais escient. Il est facile d'arrêter de nombreux systèmes à un arrêt pratique simplement en envoyant de nombreuses valeurs qui sont hachées dans le même compartiment.

5
juhist