xor
est une fonction par défaut dangereuse à utiliser lors du hachage. C'est mieux que and
et or
, mais cela ne dit pas grand-chose.
xor
est symétrique, donc l'ordre des éléments est perdu. Ainsi, "bad"
le hachage se combinera de la même manière que "dab"
.
xor
mappe des valeurs identiques par paires à zéro, et vous devez éviter de mapper des valeurs "communes" à zéro:
Donc, (a,a)
est mappé à 0, et est (b,b)
également mappé à 0. Comme ces paires sont presque toujours plus courantes que le hasard pourrait l'impliquer, vous vous retrouvez avec beaucoup de collisions à zéro que vous ne le devriez.
Avec ces deux problèmes, xor
finit par être un combineur de hachage qui semble à moitié décent en surface, mais pas après une inspection plus approfondie.
Sur le matériel moderne, l'ajout est généralement aussi rapide que xor
(il utilise probablement plus d'énergie pour y parvenir, certes). L'ajout de la table de vérité est similaire à celui xor
du bit en question, mais il envoie également un bit au bit suivant lorsque les deux valeurs sont 1. Cela signifie qu'il efface moins d'informations.
C'est donc hash(a) + hash(b)
mieux hash(a) xor hash(b)
que si a==b
, le résultat est hash(a)<<1
au lieu de 0.
Cela reste symétrique; donc le "bad"
et "dab"
obtenir le même résultat reste un problème. On peut casser cette symétrie pour un coût modique:
hash(a)<<1 + hash(a) + hash(b)
aka hash(a)*3 + hash(b)
. ( hash(a)
il est conseillé de calculer une fois et de stocker si vous utilisez la solution de décalage). Toute constante impaire au lieu de 3
mappera bijectivement un k
entier non signé « -bit» à elle-même, car la mappe sur des entiers non signés est mathématique modulo 2^k
pour certains k
, et toute constante impaire est relativement première 2^k
.
Pour une version encore plus sophistiquée, nous pouvons examiner boost::hash_combine
, ce qui est effectivement:
size_t hash_combine( size_t lhs, size_t rhs ) {
lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2);
return lhs;
}
ici nous additionnons quelques versions décalées de seed
avec une constante (qui est fondamentalement aléatoire 0
s et 1
s - en particulier c'est l'inverse du nombre d'or comme une fraction de virgule fixe de 32 bits) avec un ajout et un xor. Cette symétrie pauses et présente quelques « bruit » si les valeurs sont pauvres entrants hachés (c. -à imaginer tous les composants hash à 0 - les poignées au- dessus bien, générer un frottis de 1
et 0
. S après chaque moissonneuse - batteuse Mon naïve 3*hash(a)+hash(b)
sorties simplement 0
en ce cas).
(Pour ceux qui ne sont pas familiers avec C / C ++, a size_t
est une valeur entière non signée qui est suffisamment grande pour décrire la taille de tout objet en mémoire. Sur un système 64 bits, il s'agit généralement d'un entier non signé 64 bits. Sur un système 32 bits , un entier non signé de 32 bits.)