Attualmente sto lavorando sulla scelta di un paio di funzioni di hashing per uso generico da utilizzare nelle sostituzioni Object.GetHashCode()
. Inizialmente, su raccomandazione di this site ho iniziato con ELF. La mia implementazione C# è qui sotto:Perché un tasso di collisione così elevato con la mia implementazione hash ELF
public int Generate(byte[] key) {
const uint c = 0xf0000000;
uint h = 0,
g = 0;
unchecked {
for (int i = 0, len = key.Length; i < len; i++) {
h = (h << 4) + key[i];
if ((g = h & c) != 0)
h ^= g >> 24;
h &= ~g;
}
}
return (int)h;
}
Il mio banco di prova è costituito da 524.288 valori unici divisi in (256-2048) stringhe brevi (1-64) e lunghe (set di caratteri ASCII limitata) e dati binari arbitrari (131,072 ciascuna) per testare ogni algoritmo in una varietà di circostanze.
Comprendo anche i limiti di questo scenario di test. Un algoritmo di hashing può funzionare eccezionalmente bene con l'hashing, ad esempio gli URL, ma essere pessimi con hashing JPG o qualcosa del genere. Stringhe casuali/binari mi sembrano il miglior punto di partenza per scegliere una funzione generica. Sono felice di sentire i motivi per cui questo non è il caso.
Ho eseguito 3 esecuzioni di test separate (generando un nuovo set di stringhe/byte casuali ogni volta) e una media dei risultati.
L'algoritmo ELF prodotto un certo numero di collisioni orribile in confronto agli altri algoritmi sono test:
- stringhe brevi: 817 collisioni (~ 0.5% non riesce rate).
- Short binary: 550 collisioni (~ 0,4% tasso fallito)
- Lunghe stringhe/binario: 34 collisioni (~ 0,025% percentuale di errore).
Per posizionare questo contesto, gli altri 3 algoritmi che ho testato hanno prodotto in media tra 3-10 collisioni in media per gli stessi test. E 'anche tra i più lenti dei 4, quindi a questo punto sembra essere del tutto inutile.
risultati completi:
Strings Binary Algorithm short:long short:long ELF 817:40 550:28 FNV 1.6:2 0.6:2.6 OAT 9:9.6 14:5 Jenkins* 2:1.3 12:3.6 * A close approximation of the lookup3 hash function.
Così, per gli stessi campioni casuali che ELF sta lottando su (ho generato 3 set separati), tutti gli altri algoritmi testati stanno producendo modo modo meno collisioni.
Ho cercato varianti dell'algoritmo ELF, ma i pochi esempi che ho trovato sembrano coerenti con ciò che ho implementato. L'unica variazione che ho visto era su questa domanda SO: Using ELF to produce a tweaked hashmap. Questa variazione include h &= g >> 24
all'interno del blocco if e taglia il risultato a 31 bit. Ho provato quella variazione e ha prodotto gli stessi risultati terribili.
Ho fatto qualcosa di sottilmente ma orribilmente sbagliato? Non riesco a capire perché si stia comportando così male visto che è presumibilmente ampiamente usato in Unix.
Credo solo che i progettisti di tabelle di simboli ELF in cui meno esperti di hashing di te sono ... –
Qual è la domanda - "La mia implementazione di ELF è corretta?" – Ben
@ Ben - Sì. Titolo della domanda aggiornato per essere più chiaro. –