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 Numbers
daha 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-1a
iyisi ve DJB2x
en 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_basis
ve FNV_prime
dö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 SuperFastHash
bulduğ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 Murmur
diğ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