Ogólnie rzecz biorąc, powinieneś wybrać mnożnik, który jest zgodny z rozmiarem twojego skrótu ( 2^32w przykładzie) i nie ma z nim wspólnych czynników. W ten sposób funkcja skrótu równomiernie pokrywa całą przestrzeń skrótu.
Edycja: Największą wadą tej funkcji skrótu jest to, że zachowuje podzielność, więc jeśli wszystkie liczby całkowite są podzielne przez 2 lub 4 (co nie jest rzadkością), ich skróty też będą. Jest to problem w tabelach haszujących - możesz skończyć z tylko 1/2 lub 1/4 używanych pojemników.
To naprawdę zła funkcja skrótu, choć związana ze słynnym nazwiskiem.
Seun Osewa
5
Nie jest to wcale zła funkcja skrótu, jeśli jest używana z głównymi rozmiarami tabel. Służy również do haszowania zamkniętego . Jeśli wartości skrótu nie są równomiernie rozłożone, mieszanie multiplikatywne zapewnia, że kolizje jednej wartości prawdopodobnie nie będą „zakłócać” elementów z innymi wartościami skrótu.
Paolo Bonzini
11
Dla ciekawskich tę stałą wybrano jako rozmiar skrótu (2 ^ 32) podzielony przez Phi
awdz9nld
7
Paolo: Metoda Knutha jest „zła” w tym sensie, że nie powoduje lawiny na górnych bitach
awdz9nld
9
Przy bliższym przyjrzeniu się okazuje się, że 2654435761 jest w rzeczywistości liczbą pierwszą. Więc prawdopodobnie dlatego został wybrany zamiast 2654435769.
karadoc
149
Odkryłem, że następujący algorytm zapewnia bardzo dobry rozkład statystyczny. Każdy bit wejściowy wpływa na każdy bit wyjściowy z około 50% prawdopodobieństwem. Nie ma kolizji (każde wejście skutkuje innym wyjściem). Algorytm jest szybki, z wyjątkiem sytuacji, gdy procesor nie ma wbudowanej jednostki mnożenia liczb całkowitych. Kod C, zakładając, że intjest 32 bitów (Java, zastępuje >>się >>>i usunięcia unsigned)
unsignedint hash(unsignedint x){
x =((x >>16)^ x)*0x45d9f3b;
x =((x >>16)^ x)*0x45d9f3b;
x =(x >>16)^ x;return x;}
Magiczna liczba została obliczona za pomocą specjalnego wielowątkowego programu testowego, który działał przez wiele godzin, który oblicza efekt lawiny (liczba bitów wyjściowych, które zmieniają się przy zmianie jednego bitu wejściowego; powinna wynosić średnio prawie 16), niezależność zmiany bitów wyjściowych (bity wyjściowe nie powinny od siebie zależeć) oraz prawdopodobieństwo zmiany każdego bitu wyjściowego w przypadku zmiany dowolnego bitu wejściowego. Obliczone wartości są lepsze niż 32-bitowy finalizator używany przez MurmurHash i prawie tak samo dobre (niezupełnie), jak przy użyciu AES . Niewielką zaletą jest to, że ta sama stała jest używana dwukrotnie (przy ostatnim testowaniu przyspieszyło to nieco, nie jestem pewien, czy nadal tak jest).
Można odwrócić proces (uzyskać wartość wejściowy z hash), jeśli zastąpi 0x45d9f3bsię 0x119de1f3(w Liczba odwrotna ):
unsignedint unhash(unsignedint x){
x =((x >>16)^ x)*0x119de1f3;
x =((x >>16)^ x)*0x119de1f3;
x =(x >>16)^ x;return x;}
W przypadku liczb 64-bitowych sugeruję użycie następujących, nawet myśląc, że może nie być najszybszy. Ten jest oparty na splitmix64 , który wydaje się być oparty na artykule na blogu Better Bit Mixing (mix 13).
uint64_t hash(uint64_t x){
x =(x ^(x >>30))* UINT64_C(0xbf58476d1ce4e5b9);
x =(x ^(x >>27))* UINT64_C(0x94d049bb133111eb);
x = x ^(x >>31);return x;}
Java, użytkowania long, dodać Ldo stałej, wymienić >>z >>>i usunąć unsigned. W takim przypadku cofanie jest bardziej skomplikowane:
uint64_t unhash(uint64_t x){
x =(x ^(x >>31)^(x >>62))* UINT64_C(0x319642b2d24d8ec3);
x =(x ^(x >>27)^(x >>54))* UINT64_C(0x96de1b173f119089);
x = x ^(x >>30)^(x >>60);return x;}
Aktualizacja: Możesz również przyjrzeć się projektowi Hash Function Prospector , w którym wymienione są inne (prawdopodobnie lepsze) stałe.
pierwsze dwie linie są dokładnie takie same! czy jest tu literówka?
Kshitij Banerjee
3
Nie, to nie jest literówka, druga linia dalej miesza bity. Używanie tylko jednego mnożenia nie jest tak dobre.
Thomas Mueller
3
Zmieniłem magiczną liczbę, ponieważ zgodnie z przypadkiem testowym zapisałem wartość 0x45d9f3b zapewnia lepsze zamieszanie i dyfuzję , szczególnie, że jeśli jeden bit wyjściowy się zmienia, każdy inny bit wyjściowy zmienia się z mniej więcej tym samym prawdopodobieństwem (oprócz tego wszystkie bity wyjściowe zmieniają się wraz z to samo prawdopodobieństwo, jeśli zmienia się bit wejściowy). Jak zmierzyłeś wartość 0x3335b369, która działa lepiej dla Ciebie? Czy jest dla Ciebie int 32-bitowy?
Thomas Mueller
3
Szukam fajnej funkcji skrótu dla 64-bitowych int bez znaku do 32-bitowych int bez znaku. Czy w takim przypadku powyżej magiczna liczba będzie taka sama? Przesunąłem 32 bity zamiast 16 bitów.
alessandro
3
Uważam, że w takim przypadku większy czynnik byłby lepszy, ale trzeba by było przeprowadzić kilka testów. Lub (to jest to, co robię) najpierw używam, x = ((x >> 32) ^ x)a następnie używam mnożenia 32-bitowego powyżej. Nie wiem, co jest lepsze. Możesz również spojrzeć na 64-bitowy finalizator dla Murmur3
Thomas Mueller
29
Zależy od sposobu dystrybucji danych. Prosty licznik to najprostsza funkcja
f(i)= i
będzie dobry (podejrzewam, że optymalny, ale nie mogę tego udowodnić).
Problem polega na tym, że często mamy duże zbiory liczb całkowitych, które są podzielne przez wspólny czynnik (adresy pamięci wyrównane do słów itp.). Teraz, jeśli zdarzy się, że twoja tablica haszująca jest podzielna przez ten sam współczynnik, otrzymasz tylko połowę (lub 1/4, 1/8 itd.) Użytych pojemników.
Rafał Dowgird
8
@Rafal: Dlatego odpowiedź brzmi „dla prostego licznika” i „Zależy od sposobu dystrybucji danych”
@JuandeCarrion To jest mylące, ponieważ nie jest to używany skrót. Po przejściu do korzystania z mocy dwóch rozmiarów tabel Java ponownie haszuje każdy zwracany hash .hashCode(), patrz tutaj .
Esailija
8
Funkcja tożsamości jest dość bezużyteczna jako skrót w wielu praktycznych zastosowaniach ze względu na swoje właściwości dystrybucyjne (lub ich brak), chyba że, oczywiście, lokalizacja jest pożądanym atrybutem
awdz9nld
12
Szybkie i dobre funkcje skrótu mogą składać się z szybkich permutacji o mniejszych właściwościach, takich jak
mnożenie przez nieparzystą liczbę całkowitą
obroty binarne
xorshift
Aby uzyskać funkcję haszującą o doskonałych właściwościach, jak pokazano w przypadku PCG do generowania liczb losowych.
W rzeczywistości jest to również przepis rrxmrrxmsx_0 i szmery hash używane, świadomie lub nieświadomie.
Osobiście znalazłem
uint64_t xorshift(constuint64_t& n,int i){return n^(n>>i);}uint64_t hash(constuint64_t& n){uint64_t p =0x5555555555555555ull;// pattern of alternating 0 and 1uint64_t c =17316035218449499591ull;// random uneven integer constant; return c*xorshift(p*xorshift(n,32),32);}
być wystarczająco dobrym.
Dobra funkcja skrótu powinna
dążyć do tego, aby nie tracić informacji, jeśli to możliwe i mieć jak najmniej kolizji
kaskadować tak dużo i tak równomiernie, jak to możliwe, tj. każdy bit wejściowy powinien odwracać każdy bit wyjściowy z prawdopodobieństwem 0,5.
Przyjrzyjmy się najpierw funkcji tożsamości. Spełnia wymagania 1., ale nie 2.:
Bit wejściowy n określa wyjściowy bit n z korelacją 100% (czerwony) i żadnymi innymi, dlatego są one niebieskie, dając doskonałą czerwoną linię w poprzek.
Xorshift (n, 32) nie jest dużo lepszy, dając półtorej linii. Wciąż satysfakcjonujący 1., ponieważ jest odwracalny przy drugim zastosowaniu.
Mnożenie przez liczbę całkowitą bez znaku jest znacznie lepsze, kaskaduje silniej i odwraca więcej bitów wyjściowych z prawdopodobieństwem 0,5, czyli tym, czego chcesz, na zielono. Spełnia 1., ponieważ dla każdej nieparzystej liczby całkowitej występuje odwrotność multiplikatywna.
Połączenie tych dwóch daje następujący wynik, wciąż spełniający 1., ponieważ połączenie dwóch funkcji bijektywnych daje kolejną funkcję bijektywną.
Drugie zastosowanie mnożenia i xorshift da następujące efekty:
Lub możesz użyć mnożenia pól Galois, takich jak GHash , stały się one dość szybkie na nowoczesnych procesorach i mają doskonałe właściwości w jednym kroku.
uint64_tconstinline gfmul(constuint64_t& i,constuint64_t& j){
__m128i I{};I[0]^=i;
__m128i J{};J[0]^=j;
__m128i M{};M[0]^=0xb000000000000000ull;
__m128i X = _mm_clmulepi64_si128(I,J,0);
__m128i A = _mm_clmulepi64_si128(X,M,0);
__m128i B = _mm_clmulepi64_si128(A,M,0);return A[0]^A[1]^B[1]^X[0]^X[1];}
gfmul: Kod wydaje się być pseudokodem, ponieważ afaik nie możesz używać nawiasów z __m128i. Wciąż bardzo interesujące. Wydaje się, że w pierwszym wierszu jest napisane „weź zjednostkowany __m128i (I) i xoruj go z (parametr) i. Czy mam to odczytać jako zainicjuj I z 0 i xor z i? Jeśli tak, czy będzie to to samo, co załaduj I z i i wykonać nie (operację) na mnie?
stycznia
@Jan chciałbym to zrobić __m128i I = i; //set the lower 64 bits, ale nie mogę, więc używam ^=. 0^1 = 1dlatego nie jest nieskrępowany. Jeśli chodzi o inicjalizację za pomocą {}mojego kompilatora, nigdy nie narzekałem, może to nie jest najlepsze rozwiązanie, ale chcę z tym zainicjować wszystko do 0, więc mogę zrobić ^=lub |=. Myślę, że oparłem ten kod na tym poście, który również podaje inwersję, bardzo przydatne: D
Wolfgang Brehm
6
Ta strona zawiera listę kilku prostych funkcji skrótu, które generalnie są przyzwoite, ale każdy prosty skrót ma patologiczne przypadki, w których nie działa dobrze.
W Eternally Confuzzled znajduje się ładny przegląd niektórych algorytmów mieszania . Poleciłbym jednorazowy hash Boba Jenkinsa, który szybko osiąga lawinę i dlatego może być używany do wydajnego wyszukiwania tabeli skrótów.
To dobry artykuł, ale koncentruje się na haszowaniu kluczy łańcuchowych, a nie liczb całkowitych.
Adrian Mouat
Dla jasności, chociaż metody opisane w artykule działałyby na liczbach całkowitych (lub można je było dostosować), zakładam, że istnieją bardziej wydajne algorytmy dla liczb całkowitych.
Adrian Mouat
2
Odpowiedź zależy od wielu rzeczy, takich jak:
Gdzie zamierzasz go zatrudnić?
Co próbujesz zrobić z haszem?
Czy potrzebujesz kryptograficznie bezpiecznej funkcji skrótu?
Proponuję przyjrzeć się rodzinie funkcji skrótu Merkle-Damgard, takich jak SHA-1 itp
Nie sądzę, abyśmy mogli powiedzieć, że funkcja skrótu jest „dobra” bez wcześniejszej znajomości danych! i nie wiedząc, co z tym zrobisz.
Istnieją lepsze struktury danych niż tabele skrótów dla nieznanych rozmiarów danych (zakładam, że robisz haszowanie dla tabeli skrótów tutaj). Osobiście użyłbym tablicy mieszającej, gdy wiem, że mam „skończoną” liczbę elementów, które muszą być przechowywane w ograniczonej ilości pamięci. Spróbowałbym przeprowadzić szybką analizę statystyczną moich danych, zobaczyć, jak są one dystrybuowane itp., Zanim zacznę myśleć o mojej funkcji skrótu.
W przypadku losowych wartości skrótu niektórzy inżynierowie stwierdzili, że liczba pierwsza złotego podziału (2654435761) jest złym wyborem. Wyniki moich testów wykazały, że to nieprawda; zamiast tego 2654435761 dystrybuuje wartości skrótu całkiem dobrze.
mapowanie domeny wartości skrótu do domeny indeksu zasobnika; to znaczy przekonwertuj wartość skrótu na indeks zasobnika przez operację logiczną i operacyjną z (hash_table_size - 1), jak pokazano w Hash_UInt_GRPrimeNumber ();
obliczyć liczbę kolizji każdego wiadra;
zapisz zasobnik, który nie został zmapowany, to znaczy pusty zasobnik;
znaleźć maksymalną liczbę kolizji wszystkich wiader; to znaczy najdłuższa długość łańcucha;
Z moich wyników testów stwierdziłem, że Golden Ratio Prime Number zawsze ma mniej pustych kubłów lub zero pustych kubłów i najkrótszą długość łańcucha kolizji.
Niektóre funkcje skrótu dla liczb całkowitych są uważane za dobre, ale wyniki testów pokazują, że gdy total_data_entry / total_bucket_number = 3, najdłuższy łańcuch jest większy niż 10 (maksymalna liczba kolizji> 10), a wiele segmentów nie jest mapowanych (puste segmenty ), co jest bardzo złe w porównaniu z wynikiem zerowego pustego wiadra i najdłuższego łańcucha 3 przez Golden Ratio Prime Number Hashing.
Przy okazji, z wynikami moich testów stwierdziłem, że jedna wersja funkcji skrótu shifting-xor jest całkiem dobra (jest wspólna dla mikera).
Ale dlaczego nie zmienić produktu we właściwy sposób, aby zachować najbardziej mieszane części? Tak to miało działać
harold
1
@harold, liczba pierwsza ze złotym podziałem jest starannie dobrana, choć myślę, że nie zrobi to żadnej różnicy, ale sprawdzę, czy jest znacznie lepsza z „najbardziej mieszanymi bitami”. Chodzi mi o to, że „To nie jest dobry wybór”. nie jest prawdą, jak pokazują wyniki testów, wystarczy chwycić dolną część bitów, co jest wystarczająco dobre, a nawet lepsze niż wiele funkcji skrótu.
Chen-ChungChia
(2654435761, 4295203489) to złoty stosunek liczb pierwszych.
Chen-ChungChia
(1640565991, 2654435761) to także złoty stosunek liczb pierwszych.
Chen-ChungChia
@harold, Przesunięcie produktu w prawo staje się gorsze, nawet jeśli przesunięcie w prawo o 1 pozycję (podzielone przez 2), nadal się pogarsza (chociaż nadal zero pustego wiadra, ale najdłuższa długość łańcucha jest większa); przesuwając się w prawo o więcej pozycji, wynik staje się gorszy. Czemu? Myślę, że powód jest taki: przesunięcie produktu w prawo powoduje, że więcej wartości skrótu nie jest względnie pierwsze, tylko moje przypuszczenie, prawdziwy powód dotyczy teorii liczb.
Chen-ChungChia
1
Używam splitmix64(spiczasty Thomasa Muellera odpowiedzi ) odkąd znalazłem ten wątek. Jednak ostatnio natknąłem się na rrxmrrxmsx_0 Pelle Evensena , który dał znacznie lepszy rozkład statystyczny niż oryginalny finalizator MurmurHash3 i jego następcy ( splitmix64i inne miksy). Oto fragment kodu w C:
#include<stdint.h>staticinlineuint64_t ror64(uint64_t v,int r){return(v >> r)|(v <<(64- r));}uint64_t rrxmrrxmsx_0(uint64_t v){
v ^= ror64(v,25)^ ror64(v,50);
v *=0xA24BAED4963EE407UL;
v ^= ror64(v,24)^ ror64(v,49);
v *=0x9FB21C651E98DF25UL;return v ^ v >>28;}
Pelle zapewnia również dogłębną analizę 64-bitowego miksera używanego w ostatnim etapie MurmurHash3i nowszych wariantach.
Ta funkcja nie jest bijektywna. Dla wszystkich v, gdzie v = ror (v, 25), czyli dla wszystkich 0 i wszystkich 1, da ten sam wynik w dwóch miejscach. Dla wszystkich wartości v = ror64 (v, 24) ^ ror64 (v, 49), które są co najmniej dwa i takie same z v = ror (v, 28), dając kolejne 2 ^ 4, w sumie około 22 niepotrzebnych kolizji . Dwie aplikacje splitmix są prawdopodobnie równie dobre i równie szybkie, ale nadal odwracalne i bezkolizyjne.
Odpowiedzi:
Metoda multiplikatywna Knutha:
Ogólnie rzecz biorąc, powinieneś wybrać mnożnik, który jest zgodny z rozmiarem twojego skrótu (
2^32
w przykładzie) i nie ma z nim wspólnych czynników. W ten sposób funkcja skrótu równomiernie pokrywa całą przestrzeń skrótu.Edycja: Największą wadą tej funkcji skrótu jest to, że zachowuje podzielność, więc jeśli wszystkie liczby całkowite są podzielne przez 2 lub 4 (co nie jest rzadkością), ich skróty też będą. Jest to problem w tabelach haszujących - możesz skończyć z tylko 1/2 lub 1/4 używanych pojemników.
źródło
Odkryłem, że następujący algorytm zapewnia bardzo dobry rozkład statystyczny. Każdy bit wejściowy wpływa na każdy bit wyjściowy z około 50% prawdopodobieństwem. Nie ma kolizji (każde wejście skutkuje innym wyjściem). Algorytm jest szybki, z wyjątkiem sytuacji, gdy procesor nie ma wbudowanej jednostki mnożenia liczb całkowitych. Kod C, zakładając, że
int
jest 32 bitów (Java, zastępuje>>
się>>>
i usunięciaunsigned
)Magiczna liczba została obliczona za pomocą specjalnego wielowątkowego programu testowego, który działał przez wiele godzin, który oblicza efekt lawiny (liczba bitów wyjściowych, które zmieniają się przy zmianie jednego bitu wejściowego; powinna wynosić średnio prawie 16), niezależność zmiany bitów wyjściowych (bity wyjściowe nie powinny od siebie zależeć) oraz prawdopodobieństwo zmiany każdego bitu wyjściowego w przypadku zmiany dowolnego bitu wejściowego. Obliczone wartości są lepsze niż 32-bitowy finalizator używany przez MurmurHash i prawie tak samo dobre (niezupełnie), jak przy użyciu AES . Niewielką zaletą jest to, że ta sama stała jest używana dwukrotnie (przy ostatnim testowaniu przyspieszyło to nieco, nie jestem pewien, czy nadal tak jest).
Można odwrócić proces (uzyskać wartość wejściowy z hash), jeśli zastąpi
0x45d9f3b
się0x119de1f3
(w Liczba odwrotna ):W przypadku liczb 64-bitowych sugeruję użycie następujących, nawet myśląc, że może nie być najszybszy. Ten jest oparty na splitmix64 , który wydaje się być oparty na artykule na blogu Better Bit Mixing (mix 13).
Java, użytkowania
long
, dodaćL
do stałej, wymienić>>
z>>>
i usunąćunsigned
. W takim przypadku cofanie jest bardziej skomplikowane:Aktualizacja: Możesz również przyjrzeć się projektowi Hash Function Prospector , w którym wymienione są inne (prawdopodobnie lepsze) stałe.
źródło
x = ((x >> 32) ^ x)
a następnie używam mnożenia 32-bitowego powyżej. Nie wiem, co jest lepsze. Możesz również spojrzeć na 64-bitowy finalizator dla Murmur3Zależy od sposobu dystrybucji danych. Prosty licznik to najprostsza funkcja
będzie dobry (podejrzewam, że optymalny, ale nie mogę tego udowodnić).
źródło
.hashCode()
, patrz tutaj .Szybkie i dobre funkcje skrótu mogą składać się z szybkich permutacji o mniejszych właściwościach, takich jak
Aby uzyskać funkcję haszującą o doskonałych właściwościach, jak pokazano w przypadku PCG do generowania liczb losowych.
W rzeczywistości jest to również przepis rrxmrrxmsx_0 i szmery hash używane, świadomie lub nieświadomie.
Osobiście znalazłem
być wystarczająco dobrym.
Dobra funkcja skrótu powinna
Przyjrzyjmy się najpierw funkcji tożsamości. Spełnia wymagania 1., ale nie 2.:
Bit wejściowy n określa wyjściowy bit n z korelacją 100% (czerwony) i żadnymi innymi, dlatego są one niebieskie, dając doskonałą czerwoną linię w poprzek.
Xorshift (n, 32) nie jest dużo lepszy, dając półtorej linii. Wciąż satysfakcjonujący 1., ponieważ jest odwracalny przy drugim zastosowaniu.
Mnożenie przez liczbę całkowitą bez znaku jest znacznie lepsze, kaskaduje silniej i odwraca więcej bitów wyjściowych z prawdopodobieństwem 0,5, czyli tym, czego chcesz, na zielono. Spełnia 1., ponieważ dla każdej nieparzystej liczby całkowitej występuje odwrotność multiplikatywna.
Połączenie tych dwóch daje następujący wynik, wciąż spełniający 1., ponieważ połączenie dwóch funkcji bijektywnych daje kolejną funkcję bijektywną.
Drugie zastosowanie mnożenia i xorshift da następujące efekty:
Lub możesz użyć mnożenia pól Galois, takich jak GHash , stały się one dość szybkie na nowoczesnych procesorach i mają doskonałe właściwości w jednym kroku.
źródło
__m128i I = i; //set the lower 64 bits
, ale nie mogę, więc używam^=
.0^1 = 1
dlatego nie jest nieskrępowany. Jeśli chodzi o inicjalizację za pomocą{}
mojego kompilatora, nigdy nie narzekałem, może to nie jest najlepsze rozwiązanie, ale chcę z tym zainicjować wszystko do 0, więc mogę zrobić^=
lub|=
. Myślę, że oparłem ten kod na tym poście, który również podaje inwersję, bardzo przydatne: DTa strona zawiera listę kilku prostych funkcji skrótu, które generalnie są przyzwoite, ale każdy prosty skrót ma patologiczne przypadki, w których nie działa dobrze.
źródło
32-bitowa metoda multiplikatywna (bardzo szybka) patrz @rafal
32-bity i 64-bity (dobra dystrybucja) pod adresem: MurmurHash
źródło
W Eternally Confuzzled znajduje się ładny przegląd niektórych algorytmów mieszania . Poleciłbym jednorazowy hash Boba Jenkinsa, który szybko osiąga lawinę i dlatego może być używany do wydajnego wyszukiwania tabeli skrótów.
źródło
Odpowiedź zależy od wielu rzeczy, takich jak:
Proponuję przyjrzeć się rodzinie funkcji skrótu Merkle-Damgard, takich jak SHA-1 itp
źródło
Nie sądzę, abyśmy mogli powiedzieć, że funkcja skrótu jest „dobra” bez wcześniejszej znajomości danych! i nie wiedząc, co z tym zrobisz.
Istnieją lepsze struktury danych niż tabele skrótów dla nieznanych rozmiarów danych (zakładam, że robisz haszowanie dla tabeli skrótów tutaj). Osobiście użyłbym tablicy mieszającej, gdy wiem, że mam „skończoną” liczbę elementów, które muszą być przechowywane w ograniczonej ilości pamięci. Spróbowałbym przeprowadzić szybką analizę statystyczną moich danych, zobaczyć, jak są one dystrybuowane itp., Zanim zacznę myśleć o mojej funkcji skrótu.
źródło
W przypadku losowych wartości skrótu niektórzy inżynierowie stwierdzili, że liczba pierwsza złotego podziału (2654435761) jest złym wyborem. Wyniki moich testów wykazały, że to nieprawda; zamiast tego 2654435761 dystrybuuje wartości skrótu całkiem dobrze.
Rozmiar tablicy mieszania musi być potęgą dwóch.
Napisałem program testowy do oceny wielu funkcji skrótu dla liczb całkowitych, wyniki pokazują, że GRPrimeNumber to całkiem dobry wybór.
Próbowałem:
Z moich wyników testów stwierdziłem, że Golden Ratio Prime Number zawsze ma mniej pustych kubłów lub zero pustych kubłów i najkrótszą długość łańcucha kolizji.
Niektóre funkcje skrótu dla liczb całkowitych są uważane za dobre, ale wyniki testów pokazują, że gdy total_data_entry / total_bucket_number = 3, najdłuższy łańcuch jest większy niż 10 (maksymalna liczba kolizji> 10), a wiele segmentów nie jest mapowanych (puste segmenty ), co jest bardzo złe w porównaniu z wynikiem zerowego pustego wiadra i najdłuższego łańcucha 3 przez Golden Ratio Prime Number Hashing.
Przy okazji, z wynikami moich testów stwierdziłem, że jedna wersja funkcji skrótu shifting-xor jest całkiem dobra (jest wspólna dla mikera).
źródło
Używam
splitmix64
(spiczasty Thomasa Muellera odpowiedzi ) odkąd znalazłem ten wątek. Jednak ostatnio natknąłem się na rrxmrrxmsx_0 Pelle Evensena , który dał znacznie lepszy rozkład statystyczny niż oryginalny finalizator MurmurHash3 i jego następcy (splitmix64
i inne miksy). Oto fragment kodu w C:Pelle zapewnia również dogłębną analizę 64-bitowego miksera używanego w ostatnim etapie
MurmurHash3
i nowszych wariantach.źródło