% Operatörünü kullanmadan iyi dağıtılmış bir karma tablo uygulamak mümkün müdür?


11

C # hızlı, iyi dağıtılmış bir karma tablo uygulamak arıyorum. Ben rasgele bir karma kodu alır ve "bu" kovalar indekslemek için kullanılabilir "kısıtlama" benim karma kısıtlama işlevini seçme konusunda sorun yaşıyorum. Şimdiye kadar gördüğüm iki seçenek var:

  • Bir yandan, kovalarınızın her zaman asal sayıda elemente sahip olduğundan emin olabilirsiniz ve hash'ı sınırlamak için onu kova sayısına göre modüle edebilirsiniz. Aslında, .NET'in Sözlüğü bunu yapar . Bu yaklaşımdaki sorun,% kullanımının diğer işlemlere kıyasla son derece yavaş olmasıdır; Eğer bakarsak Agner Sis kullanım tabloları , idiv(% için oluşturulmuş olur montaj kodudur) yeni Intel işlemciler için ~ 25 döngü bir talimat gecikme vardır. Yaklaşık 3 için bu karşılaştırın mulgibi bitsel ops için, veya 1 and, orya da xor.

  • Öte yandan, kova sayısının her zaman 2 gücü olabilir. Hala karma modülünü hesaplamanız gerekecek, böylece dizinin dışında indeksleme girişiminde bulunmayacaksınız, ancak bu sefer daha ucuz olacak . 2'nin kuvvetleri % Niçin sadece & (N - 1)kısıtlama olduğu için, kısıtlama sadece 1-2 döngü alan bir maskeleme işlemine indirgenir. Bu, Google'ın seyrekliği tarafından yapılır . Bunun dezavantajı, iyi karmalar sağlamak için kullanıcılara güvenmemiz; karmayı maskelemek aslında karmanın bir kısmını keser, bu yüzden artık karmanın tüm parçalarını hesaba katmıyoruz. Kullanıcının karması eşit olmayan bir şekilde dağılmışsa, örneğin yalnızca daha yüksek bitler doldurulur veya alt bitler tutarlı bir şekilde aynı ise, bu yaklaşım çok daha yüksek çarpışma oranlarına sahiptir.

Her iki dünyanın da en iyisine sahip kullanabileceğim bir algoritma arıyorum: karma tüm bitlerini hesaba katar ve% kullanmaktan daha hızlıdır. Mutlaka bir modül olmak zorunda değildir, sadece aralıkta olması garanti edilen bir şeydir 0..N-1(burada N, kovaların uzunluğudur) ve tüm yuvalar için bile dağılıma sahiptir. Böyle bir algoritma var mı?

Yardım için teşekkürler.


1
Yukarı bak çığ etkisini , hem de içinde açıklama murmurhash3 (smhasher) . Ancak, sorunuzdaki temel nokta, daha iyi bir karma işlevi benimsenerek ele alınmaz. Bunun yerine, kullanıcıların neden ilk etapta aynı daha iyi hash fonksiyonunu benimsemeleri ve karşı önlemler (örneğin, kötü niyetli olarak tembelmiş gibi) istemesi hakkında bir sorudur.
rwong


Hızlı modulo için (2^N +/- 1)bkz. Stackoverflow.com/questions/763137/…
rwong

@rwong Üzgünüm, ancak yorumunuzun yazımla ne ilgisi olduğundan emin değilim. Ben kullanıcı tarafından sağlanan karma kontrol etmeyin, bu yüzden daha iyi bir karma işlevi aramıyorum. "Kötü niyetli tembel kullanıcılar" ile ne demek istediğinizi de anlamıyorum.
James Ko

4
Karma işlevi zayıfsa, karma tablosu uygulayıcının kötü dağıtımı "düzeltmek" için yapabileceği hiçbir şey yoktur. Bir asal sayı olan Modulo, zayıf bir karmayı onarmaz. Bir asal sayının katları olan çıktı olarak üreten bir hash fonksiyonu düşünün. Gerçek üretim kodunda böyle bir sorun gördüm.
Frank Hileman

Yanıtlar:


9

Modern karma tablo uygulamaları modulo işlevini kullanmaz. Genellikle iki boyutlu masaların gücünü kullanırlar ve gereksiz bitleri keserler. İdeal bir karma fonksiyonu buna izin verir. Asal sayı tablosu boyutları ile kombine edilmiş modulo kullanımı, genellikle .net gelişiminde olduğu gibi, karma işlevlerinin genellikle zayıf olduğu günlerde ortaya çıkmıştır. Modern bir hash fonksiyonu olan SipHash hakkında okumanızı , sonra xxHash gibi diğer modern fonksiyonlar hakkında okumanızı tavsiye ederim .

.Net hash işlevlerinin neden genellikle zayıf olduğunu açıklamalıyım. .Net'te, programcılar genellikle GetHashcode'u geçersiz kılarak karma işlevlerini uygulamaya zorlanır. Ancak .net, programcı tarafından oluşturulan işlevlerin yüksek kalitede olmasını sağlamak için gerekli araçları sağlamaz:

  • karma durumun bir yapıda veya sınıfta kapsüllenmesi
  • karma durumuna yeni veriler ekleyen hash "add" işlevleri (örneğin bir bayt dizisi veya bir double ekleyin)
  • çığ üretmek için bir karma "sonlandırma" fonksiyonu
  • karma sonucunun kapsüllenmesi .net içinde bir seçim, 32 bit işaretli bir tamsayı alırsınız.

Karma işlevi sonucunu karma tablosu dizini olarak kullanma hakkında daha fazla bilgi için lütfen bu makaledeki evrensel karma biçimlerinin tanımlarına bakın: Aktarmasız çarpmalar kullanarak daha hızlı 64 bit evrensel karma


3

Tüm bitleri korurken AND kullanmak için XOR'u da kullanın.

Örneğin temp = (hash & 0xFFFF) ^ ( hash >> 16); index = (temp & 0xFF) ^ (temp >> 8);,.

Bu örnek için, hash8 bitlik bir modulo ve 32 bitlik efekt yoktur index. Bununla birlikte, DIV'den daha hızlı olup olmadığı çok fazla faktöre bağlı olan bir şeydir ve bazı durumlarda DIV'den daha yavaş olabilir (örneğin büyük karma ve küçük indeks).


Bu her zaman DIV / IDIV'den daha hızlı olacak, ancak soruma cevap verdiğini sanmıyorum index- aralıkta olacak [0..255]. Aralıktaki bir şeye ihtiyacım var , kova sayısı [0..n-1]nerede n.
James Ko

@JamesKo Ancak bir sözlük uyguluyorsanız, bölüm sayısını da kontrol edersiniz (belirli bir dereceye kadar). Yani, asal sayılar yerine, ikisinin güçlerini seçebilirsiniz. (Bunu yapmak aslında iyi bir fikir olabilir, size söyleyemem.)
19'da svick

@svick 2 kişilik güçler için basit bir maske işlemi yapabiliriz. Soruda da belirtildiği gibi, asal sayılarla bunu yapmak için ucuz bir yol arıyorum, bu yüzden kötü dağıtılmış karmalar bile ağırlanıyor.
James Ko

1

Birçok asal tamsayının modüler çarpım tersine sahip olmasından yararlanabilirsiniz. Bkz bu yazıyı . Kova dizininizi asal ve doğal olarak nispeten asal olan 2 ^ n modülünü yaparak kısıtlamalardan birini yerine getirmiş olursunuz.

Makale, bu sayıyla çarpma ve taşmayı göz ardı etme gibi bir sayı bulmak için algoritmayı, kova dizini boyutuna bölünmüş gibi aynı sonucu verecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.