Numero magico in boost :: hash_combine


94

La boost::hash_combinefunzione template prende un riferimento a un hash (chiamato seed) e un oggetto v. Secondo i documenti , si combina seedcon l'hash di vby

seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);

Vedo che questo è deterministico. Capisco perché viene utilizzato uno XOR.

Scommetto che l'aggiunta aiuta a mappare valori simili ampiamente separati in modo che le tabelle hash non si interrompano, ma qualcuno può spiegare qual è la costante magica?


Dato che su molti computer un intero rotate costa all'incirca lo stesso di uno shift ci sarebbe qualche vantaggio nel convertire l'espressione in: <code> seed ^ = hash_value (v) + 0x9e3779b9 + rotl (seed, 6) + rotr (seed, 2); </code>
John Yates

Risposte:


140

Si suppone che il numero magico sia 32 bit casuali, dove ciascuno è ugualmente probabile che sia 0 o 1, e senza una semplice correlazione tra i bit. Un modo comune per trovare una stringa di tali bit è usare l'espansione binaria di un numero irrazionale; in questo caso, quel numero è il reciproco del rapporto aureo:

phi = (1 + sqrt(5)) / 2
2^32 / phi = 0x9e3779b9

Quindi l'inclusione di questo numero cambia "in modo casuale" ogni bit del seme; come dici tu, questo significa che i valori consecutivi saranno molto distanti. Includere le versioni spostate del vecchio seme fa in modo che, anche se hash_value()ha un intervallo di valori abbastanza piccolo, le differenze verranno presto distribuite su tutti i bit.


14
Freddo! Mi piace quando la teoria dei numeri diventa improvvisamente utile :)
Fred Foo

8
@larsmans Mi piace il tuo uso di "improvvisamente" - è molto appropriato! La teoria dei numeri è come "sì, è carino ... ma ho un vero lavoro da fare, mi dispiace" nel 99% dei casi. E poi, come dici tu, "all'improvviso", la teoria dei numeri è super utilissima. Non è come un martello in cui è piuttosto utile per un gran numero di cose. Invece, è come un bisturi estremamente utile per un piccolo numero di cose.
corsiKa

5
@SamKellett Funzionerebbe ancora meglio se usassi il numero corretto di parentesi e ottenessi0x9e3779b97f4a7800
Barry,

5
Poiché il numero in virgola mobile di Python non ha una precisione sufficiente, i rapporti aurei a 64 bit sopra non sono corretti. Il risultato effettivo dovrebbe essere 0x9e3779b97f4a7c15.
kennytm

1
@kennytm Non intendi 0x9e3779b97f4a7c16? Voglio dire, è solo uno sconto.
bit2shift

25

Dai un'occhiata all'articolo DDJ di Bob Jenkins del 1997 . La costante magica ("sezione aurea") è spiegata come segue:

La sezione aurea è davvero un valore arbitrario. Il suo scopo è evitare di mappare tutti gli zeri su tutti gli zeri.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.