Bazı algoritmaları test ettim, hızını ve çarpışma sayısını ölçtüm.
Üç farklı anahtar seti kullandım:
Her bir korpus için çarpışma sayısı ve ortalama harcanan zaman kaydedildi.
Test ettim:
Sonuçlar
Her sonuç ortalama karma zamanı ve çarpışma sayısını içerir.
Hash Lowercase Random UUID Numbers
============= ============= =========== ==============
Murmur 145 ns 259 ns 92 ns
6 collis 5 collis 0 collis
FNV-1a 152 ns 504 ns 86 ns
4 collis 4 collis 0 collis
FNV-1 184 ns 730 ns 92 ns
1 collis 5 collis 0 collis▪
DBJ2a 158 ns 443 ns 91 ns
5 collis 6 collis 0 collis▪▪▪
DJB2 156 ns 437 ns 93 ns
7 collis 6 collis 0 collis▪▪▪
SDBM 148 ns 484 ns 90 ns
4 collis 6 collis 0 collis**
SuperFastHash 164 ns 344 ns 118 ns
85 collis 4 collis 18742 collis
CRC32 250 ns 946 ns 130 ns
2 collis 0 collis 0 collis
LoseLose 338 ns - -
215178 collis
Notlar :
Çarpışmalar gerçekten oluyor mu?
Evet. Test programımı karma çarpışmaların gerçekten olup olmadığını görmek için yazmaya başladım - ve sadece teorik bir yapı değil. Gerçekten de oluyorlar:
FNV-1 çarpışmaları
creamwove ile çarpışır quists
FNV-1a çarpışmaları
costarring ile çarpışır liquid
declinate ile çarpışır macallums
altarage ile çarpışır zinke
altarages ile çarpışır zinkes
Murmur2 çarpışmaları
cataract ile çarpışır periti
roquette ile çarpışır skivie
shawl ile çarpışır stormbound
dowlases ile çarpışır tramontane
cricketings ile çarpışır twanger
longans ile çarpışır whigs
DJB2 çarpışmaları
hetairas ile çarpışır mentioner
heliotropes ile çarpışır neurospora
depravement ile çarpışır serafins
stylist ile çarpışır subgenera
joyful ile çarpışır synaphea
redescribed ile çarpışır urites
dram ile çarpışır vivency
DJB2a çarpışmaları
haggadot ile çarpışır loathsomenesses
adorablenesses ile çarpışır rentability
playwright ile çarpışır snush
playwrighting ile çarpışır snushing
treponematoses ile çarpışır waterbeds
CRC32 çarpışmaları
codding ile çarpışır gnu
exhibiters ile çarpışır schlager
SuperFastHash çarpışmaları
dahabiah ile çarpışır drapability
encharm ile çarpışır enclave
grahams ile çarpışır gramary
- ... 79 çarpışmayı engelle ...
night ile çarpışır vigil
nights ile çarpışır vigils
finks ile çarpışır vinic
Randomnessification
Diğer sübjektif ölçü ise karmaların ne kadar rastgele dağıtıldığıdır. Sonuçta elde edilen HashTable'ların eşlenmesi verilerin ne kadar eşit dağıldığını gösterir. Tüm karma işlevleri, tabloyu doğrusal olarak eşlerken iyi dağılım gösterir:

Veya bir Hilbert Haritası olarak ( XKCD her zaman ilgilidir ):

Sayı dizelerinin ( "1",, "2"..., "216553") (örneğin, posta kodları ) eklenmesi haricinde , kalıpların karma algoritmaların çoğunda ortaya çıkmaya başladığı durumlar hariç :
SDBM :

DJB2a :

FNV-1 :

Hala bana rastgele görünen FNV-1a hariç :

Aslında, Murmur2 ile daha da iyi rastlantısallığını var gibi gözüküyor Numbersdaha FNV-1a:

FNV-1a"Sayı" haritasına baktığımda, ince dikey desenler gördüğümü düşünüyorum . Murmur ile hiçbir desen göremiyorum. Ne düşünüyorsun?
*Tablodaki ekstra , rastgeleliğin ne kadar kötü olduğunu göstermektedir. En FNV-1aiyisi ve DJB2xen kötüsü olmak:
Murmur2: .
FNV-1a: .
FNV-1: ▪
DJB2: ▪▪
DJB2a: ▪▪
SDBM: ▪▪▪
SuperFastHash: .
CRC: ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪
Loselose: ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪
▪
▪▪▪▪▪▪▪▪▪▪▪▪▪
▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪
▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪
Aslında bu programı çarpışmalardan endişe duyup duymamam gerektiğine karar vermek için yazdım : Yaparım.
Ve sonra karma fonksiyonlarının yeterince rastgele olduğundan emin olmaya başladı.
FNV-1a algoritması
FNV1 karma, 32, 64, 128, 256, 512 ve 1024 bit karma değerlerini döndüren değişkenlerle gelir.
FNV'nin-1a Algoritma olduğu:
hash = FNV_offset_basis
for each octetOfData to be hashed
hash = hash xor octetOfData
hash = hash * FNV_prime
return hash
Burada istediğiniz sabit FNV_offset_basisve FNV_primedönüş hash büyüklüğüne bağlı:
Hash Size
===========
32-bit
prime: 2^24 + 2^8 + 0x93 = 16777619
offset: 2166136261
64-bit
prime: 2^40 + 2^8 + 0xb3 = 1099511628211
offset: 14695981039346656037
128-bit
prime: 2^88 + 2^8 + 0x3b = 309485009821345068724781371
offset: 144066263297769815596495629667062367629
256-bit
prime: 2^168 + 2^8 + 0x63 = 374144419156711147060143317175368453031918731002211
offset: 100029257958052580907070968620625704837092796014241193945225284501741471925557
512-bit
prime: 2^344 + 2^8 + 0x57 = 35835915874844867368919076489095108449946327955754392558399825615420669938882575126094039892345713852759
offset: 9659303129496669498009435400716310466090418745672637896108374329434462657994582932197716438449813051892206539805784495328239340083876191928701583869517785
1024-bit
prime: 2^680 + 2^8 + 0x8d = 5016456510113118655434598811035278955030765345404790744303017523831112055108147451509157692220295382716162651878526895249385292291816524375083746691371804094271873160484737966720260389217684476157468082573
offset: 1419779506494762106872207064140321832088062279544193396087847491461758272325229673230371772250864096521202355549365628174669108571814760471015076148029755969804077320157692458563003215304957150157403644460363550505412711285966361610267868082893823963790439336411086884584107735010676915
Ayrıntılar için ana FNV sayfasına bakın.
Bütün sonuçlarım 32 bit değişkendir.
FNV-1, FNV-1a'dan daha mı iyi?
Hayır. FNV-1a her yerde daha iyi durumda. İngilizce corpus kelimesini kullanırken FNV-1a ile daha fazla çarpışma oldu:
Hash Word Collisions
====== ===============
FNV-1 1
FNV-1a 4
Şimdi küçük ve büyük harfleri karşılaştırın:
Hash lowercase word Collisions UPPERCASE word collisions
====== ========================= =========================
FNV-1 1 9
FNV-1a 4 11
Bu durumda FNV-1a, "% 400" FN-1'den daha kötü değildir, sadece% 20 daha kötüdür.
Bence en önemli paket, çarpışmalar söz konusu olduğunda iki algoritma sınıfı olması:
- nadir çarpışmalar : FNV-1, FNV-1a, DJB2, DJB2a, SDBM
- ortak çarpışmalar : SuperFastHash, Loselose
Ve sonra, karmaların ne kadar eşit dağılmış olduğu:
- üstün dağıtım: Murmur2, FNV-1a, SuperFastHas
- mükemmel dağıtım: FNV-1
- iyi dağıtım: SDBM, DJB2, DJB2a
- korkunç dağıtım: Loselose
Güncelleme
Mırıldanıyorum? Tabii neden olmasın
Güncelleme
@whatshisname bir CRC32'nin nasıl performans gösterdiğini merak etti, tabloya numaralar ekledi.
CRC32 oldukça iyi . Birkaç çarpışma, ancak daha yavaş ve 1k'lik bir arama tablosunun ek yükü.
CRC dağılımı ile ilgili tüm hatalı şeyleri koparın - benim kötü
Bugüne kadar fiili hash-tablo karma algoritması olarak FNV-1a'yı kullanacaktım . Ama şimdi Murmur2'ye geçiyorum:
- Daha hızlı
- Tüm girdi sınıflarının daha iyi tesadüfi olması
Ve gerçekten, gerçekten de SuperFastHashbulduğum algoritmada yanlış bir şeyler olduğunu umuyorum ; olduğu kadar popüler olmak çok kötü.
Güncelleme: Gönderen Google'da MurmurHash3 ana :
(1) - SuperFastHash, başka bir yerde belgelenen çok zayıf çarpışma özelliklerine sahiptir.
Sanırım sadece ben değilim.
Güncelleme: Neden Murmurdiğerlerinden daha hızlı olduğunu anladım . MurmurHash2 aynı anda dört baytta çalışır. Çoğu algoritma byte bayt :
for each octet in Key
AddTheOctetToTheHash
Bu, anahtarlar uzadıkça Murmur'un parlama şansı olduğu anlamına gelir.
Güncelleme
Raymond Chen'in zamanında gönderdiği bir yazı, "rastgele" GUID'lerin rastgele olmaları için kullanılmadığı gerçeğini yineliyor . Onlar veya alt kümeleri, karma anahtar olarak uygun değildir:
Sürüm 4 GUID algoritmasının bile tahmin edilemez olduğu garanti edilmez, çünkü algoritma rasgele sayı üretecinin kalitesini belirlemez. GUID için Wikipedia makalesi , jeneratörün kriptografik olarak güçlü olmadığı için gelecekteki ve önceki GUID'lerin rasgele sayı üreteci durumunun bilgisine dayanarak tahmin edilebileceğini öne süren birincil araştırmaları içermektedir .
Rastgele çarpışmadan kaçınma ile aynı değildir; bu nedenle, "rastgele" bir kılavuzun alt kümesini alarak kendi "karma" algoritmanızı icat etmeye çalışmak bir hata olur:
int HashKeyFromGuid(Guid type4uuid)
{
//A "4" is put somewhere in the GUID.
//I can't remember exactly where, but it doesn't matter for
//the illustrative purposes of this pseudocode
int guidVersion = ((type4uuid.D3 & 0x0f00) >> 8);
Assert(guidVersion == 4);
return (int)GetFirstFourBytesOfGuid(type4uuid);
}
Not : Yine, "rasgele GUID" i tırnak içine koyarım, çünkü GUID'lerin "rasgele" bir çeşididir. Daha doğru bir açıklama olacaktır Type 4 UUID. Fakat kimse tip 4 veya tip 1, 3 ve 5'in ne olduğunu bilmiyor. Bu yüzden onları "rastgele" GUID'ler olarak adlandırmak daha kolay.
Tüm İngilizce Kelimeler mirrors