xores una función predeterminada peligrosa para usar cuando se usa hashing. Es mejor que andy or, pero eso no dice mucho.
xores simétrico, por lo que se pierde el orden de los elementos. Entonces "bad", el hash combinará lo mismo que "dab".
xor asigna valores idénticos por pares a cero, y debe evitar asignar valores "comunes" a cero:
Por lo tanto, (a,a)se asigna a 0, y (b,b)también se asigna a 0. Como tales pares son casi siempre más comunes de lo que podría implicar la aleatoriedad, terminas con muchas colisiones en cero de lo que deberías.
Con estos dos problemas, xortermina siendo un combinador de hash que parece medio decente en la superficie, pero no después de una inspección adicional.
En el hardware moderno, agregar generalmente casi tan rápido como xor(probablemente use más potencia para lograr esto, es cierto). Agregar la tabla de verdad es similar al xorbit en cuestión, pero también envía un bit al siguiente bit cuando ambos valores son 1. Esto significa que borra menos información.
Entonces hash(a) + hash(b)es mejor que hash(a) xor hash(b)en eso si a==b, el resultado es en hash(a)<<1lugar de 0.
Esto sigue siendo simétrico; por lo que el "bad"y "dab"conseguir el mismo resultado sigue siendo un problema. Podemos romper esta simetría por un costo modesto:
hash(a)<<1 + hash(a) + hash(b)
aka hash(a)*3 + hash(b). ( hash(a)se recomienda calcular una vez y almacenar si usa la solución de turno). Cualquier constante impar en lugar de mapeará bijetivamente un entero sin signo 3" k-bit" consigo mismo, ya que el mapa en enteros sin signo es un módulo matemático 2^kpara algunos k, y cualquier constante impar es relativamente primo 2^k.
Para una versión aún más elegante, podemos examinar boost::hash_combine, que es efectivamente:
size_t hash_combine( size_t lhs, size_t rhs ) {
lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2);
return lhs;
}
aquí agregamos algunas versiones desplazadas de seedcon una constante (que es básicamente 0s y 1s al azar , en particular, es la inversa de la proporción áurea como una fracción de punto fijo de 32 bits) con alguna suma y un xor. Esto rompe la simetría, e introduce un poco de "ruido" si los valores hash entrantes son pobres (es decir, imaginar cada hashes componentes a 0 - las manijas por encima de ella, así, generar una mancha de 1y 0. S después de cada combinar mi ingenua 3*hash(a)+hash(b)simplemente generan una 0en Ese caso).
(Para aquellos que no están familiarizados con C / C ++, a size_tes un valor entero sin signo que es lo suficientemente grande como para describir el tamaño de cualquier objeto en la memoria. En un sistema de 64 bits, generalmente es un entero sin signo de 64 bits. En un sistema de 32 bits , un entero sin signo de 32 bits).