XOR neden karmaları birleştirmenin varsayılan yolu?


145

Diyelim ki iki karmanız var H(A)ve H(B)bunları birleştirmek istiyorsunuz. İki karmayı birleştirmenin iyi bir yolunun XORonlara olduğunu okudum , örneğin XOR( H(A), H(B) ).

Bulduğum en iyi açıklama, şu karma işlev yönergelerine kısaca değinilmiştir :

Kabaca rasgele dağılımlı iki sayının XORing edilmesi, kabaca rasgele dağılımlı * başka bir sayı ile sonuçlanır, ancak şimdi iki değere bağlıdır.
...
* Birleştirilecek iki sayının her bir bitinde, iki bit eşitse 0, başka bir 1 verilir. Başka bir deyişle, kombinasyonların% 50'sinde 1 verilir. Dolayısıyla, iki giriş bitinin her birinin kabaca 50-50 0 veya 1 olma şansı varsa, o zaman çıkış biti de olur.

XOR'un neden karma işlevlerini (OR veya AND vb. Yerine) birleştirmek için varsayılan işlem olması gerektiğini sezgi ve / veya matematiği açıklayabilir misiniz?


20
Sanırım az önce yaptın;)
Massa

22
XOR'un, bir "kombinasyon" da ne istediğinize bağlı olarak karmaları birleştirmek için "iyi" bir yol olabileceğini veya olmayabileceğini unutmayın. XOR değişmeli: XOR (H (A), H (B)), XOR (H (B), H (A)) 'ya eşittir. Bu, XOR'un siparişi yakalamadığı için sıralı bir değerler dizisinin bir tür karmasını oluşturmanın uygun bir yolu olmadığı anlamına gelir.
Thomas Pornin

6
Siparişle ilgili sorunun yanı sıra (yukarıdaki yorum), eşit değerlerle ilgili bir sorun var. XOR (H (1), H (1)) = 0 (herhangi bir H fonksiyonu için), XOR (H (2), H (2)) = 0 vb. Herhangi bir N için: XOR (H (N), H (N)) = 0. Eşit değerler gerçek uygulamalarda oldukça sık görülür, bu XOR'un sonucunun iyi karma olarak kabul edilmek için çok sık 0 olacağı anlamına gelir.
Andrei Galatyn

Sıralı değerler dizisi için ne kullanıyorsunuz? Diyelim ki zaman damgası veya dizin karması oluşturmak istiyorum. (MSB, LSB'den daha az önemlidir). Bu konu 1 yaşındaysa üzgünüm.
Alexis

Yanıtlar:


120

Tekdüze rastgele (1 bit) girişler olduğu varsayıldığında, AND fonksiyonu çıkış olasılığı dağılımı% 75 0ve% 25'tir 1. Tersine, OR% 25 0ve% 75'tir 1.

XOR işlevi% 50 0ve % 50'dir 1, bu nedenle tekdüze olasılık dağılımlarını birleştirmek için iyidir.

Bu doğruluk tabloları yazarak görülebilir:

 a | b | a AND b
---+---+--------
 0 | 0 |    0
 0 | 1 |    0
 1 | 0 |    0
 1 | 1 |    1

 a | b | a OR b
---+---+--------
 0 | 0 |    0
 0 | 1 |    1
 1 | 0 |    1
 1 | 1 |    1

 a | b | a XOR b
---+---+--------
 0 | 0 |    0
 0 | 1 |    1
 1 | 0 |    1
 1 | 1 |    0

Alıştırma: İki adet 1 bit girişin kaç mantıksal işlevi var ave bbu tekdüze çıkış dağılımı var? XOR neden sorunuzda belirtilen amaç için en uygun?


24
egzersize cevap verir: 16 olası farklı XXX b (0, a & b, a > b, a, a < b, b, a % b, a | b, !a & !b, a == b, !b, a >= b, !a, a <= b, !a | !b, 1)işleminden, a ve b'nin 0s ve 1s% 50-50 dağılımlarına sahip olduğunu varsayarak, aşağıdakilerin% 50-% 50 dağılımları vardır: a, b, !a, !b, a % b, a == byani, tam tersi XOR (EQUIV) de kullanılabilirdi ...
Massa

7
Greg, bu harika bir cevap. Orijinal cevabınızı gördükten ve kendi doğruluk tablolarımı yazdıktan sonra ampul benim için devam etti. @ Massa'nın dağıtımı sürdürmek için 6 uygun operasyonun nasıl olduğuna dair cevabını düşündüm. Ve a, b, !a, !bilgili girişleriyle aynı dağılıma sahip olurken , diğer girişin entropisini kaybedersiniz. Yani, XOR, hash'leri birleştirmek için en uygundur, çünkü hem a hem de b'den entropiyi yakalamak istiyoruz.
Nate Murray

1
Burada, her fonksiyonun sadece bir kez çağrıldığı durumlarda hash'ları güvenli bir şekilde birleştirmenin, her hash değerindeki bit sayısının toplamından daha az bit çıkmadan mümkün olmadığını açıklayan bir çalışma. Bu, bu cevabın doğru olmadığını göstermektedir.
Tamás Szelei

3
@Massa Hiç XOR için kullanıldığını veya eşit olmadığını gördüm.
Buge

7
Yakk'ın işaret ettiği gibi , XOR aynı değerler için sıfır ürettiği için tehlikeli olabilir. Bu araçlar (a,a)ve (b,b)çok sayıda (en?) Durumlarda büyük karma tabanlı veri yapılarına çarpışma olasılığını arttırır hem üretmek sıfır,.
Drew Noakes

170

xorkarma yaparken kullanmak için tehlikeli bir varsayılan işlevdir. Bundan daha iyidir andve orbu fazla bir şey ifade etmez.

xorsimetriktir, bu yüzden elemanların sırası kaybolur. Böylece "bad"karma ile aynı birleştirir "dab".

xor çift ​​olarak aynı değerleri sıfıra eşler ve "ortak" değerleri sıfıra eşlemekten kaçınmalısınız:

Böylece (a,a)0 ile eşlenir ve 0 ile (b,b)eşlenir. Bu çiftler neredeyse her zaman rastlantısallığın ima edebileceğinden daha yaygın olduğu için, sıfırdan çok çarpışmanız gerekir.

Bu iki problemle, xoryüzeyde yarı iyi görünen bir karma birleştirici olur, ancak daha fazla incelemeden sonra olmaz.

Modern donanımda, genellikle yaklaşık olarak hızlı ekleme xor(muhtemelen bunu çıkarmak için daha fazla güç kullanır). Eklemenin doğruluk tablosu şuna benzerxor söz konusu bite , ancak her iki değer 1 olduğunda da bir sonraki bite biraz gönderir. Bu, daha az bilgi sildiği anlamına gelir.

Yani hash(a) + hash(b)daha iyidir hash(a) xor hash(b)eğer ki a==b, sonucudurhash(a)<<1 0 yerine.

Bu simetrik kalır; böylece "bad"ve "dab"aynı sonucu elde etmek sorun olmaya devam ediyor. Bu simetriyi mütevazı bir maliyetle kırabiliriz:

hash(a)<<1 + hash(a) + hash(b)

aka hash(a)*3 + hash(b). ( hash(a)vardiya çözümünü bir kez hesaplamanız ve saklamanız tavsiye edilir). Bunun yerine herhangi bir tek sabit 3, bijektif kolarak kendi kendine bir " -bit" işaretsiz tamsayıyı eşler, çünkü işaretsiz tam sayılardaki harita 2^kbazıları için matematik modülondur kve herhangi bir tek sabit göreceli olarak asaldır 2^k.

Daha meraklı bir versiyon için, boost::hash_combineetkili bir şekilde inceleyebiliriz :

size_t hash_combine( size_t lhs, size_t rhs ) {
  lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2);
  return lhs;
}

Burada , bazı ek ve bir xor seedile bir sabit (temelde rasgele 0s ve 1s - özellikle 32 bit sabit nokta fraksiyonu olarak altın oranın tersidir) ile bazı kaydırılmış versiyonlarını ekliyoruz . Bu sonları simetri ve gelen karma değerleri yani 0'a her bileşen karmaları hayal (fakir iseler bazı "gürültü" tanıtır - Yukarıdaki kolları de, bir karalama üreten 1ve 0her peşinde birleştirmek Benim saf. 3*hash(a)+hash(b)Basitçe çıkışları a0 in O vaka).

(C / C ++ ile aşina olmayanlar için, a size_tbellekteki herhangi bir nesnenin boyutunu tanımlamak için yeterince büyük olan işaretsiz bir tamsayı değeridir. 64 bit sistemde genellikle 64 bit işaretsiz bir tamsayıdır. 32 bit sistemde , 32 bit işaretsiz bir tam sayı.)


Güzel cevap Yakk. Bu algoritma hem 32bit hem de 64bit sistemlerde eşit derecede iyi çalışıyor mu? Teşekkürler.
Dave

1
@dave için daha fazla bit ekleyin 0x9e3779b9.
Yakk - Adam Nevraumont

10
Tamam, tam olarak ... İşte tam 64bit sabit (uzun çiftler ve işaretsiz uzun uzunlarla hesaplanmıştır): 0x9e3779b97f4a7c16. İlginçtir ki hala eşit. Aynı oranın Altın Oran yerine PI kullanılarak yeniden yapılması: 0x517cc1b727220a95 üretir; bu, çift yerine gariptir, dolayısıyla muhtemelen diğer sabitten daha "asal" olur. Kullandım: std :: cout << std :: hex << (imzasız uzun uzun) ((1.0L / 3.14159265358979323846264338327950288419716939937510L) * (powl (2.0L, 64.0L))) << std :: endl; cout.precision ile (numeric_limits <long double> :: max_digits10); Tekrar teşekkürler Yakk.
Dave

2
@Bu durumlar için ters altın oran kuralını uygulayın , yaptığınız hesaplamaya eşit veya daha büyük olan ilk tek sayıdır. Öyleyse sadece 1 ekleyin. N * oranı dizisi, mod max boyutu (burada 2 ^ 64), dizideki bir sonraki değeri tam olarak en büyük 'boşluğun' ortasındaki orana yerleştirir. sayılar. Daha fazla bilgi için web'de "Fibonacci hashing" ifadesini arayın.
Scott Carey

1
@ Doğru numarayı 0.9E3779B97F4A7C15F39 olurdu ... Bağlantıya bakınız . Yuvarlama-eşit kuraldan (muhasebeciler için iyidir) acı çekiyor olabilirsiniz ya da basitçe, gerçek bir sqrt (5) sabiti ile başlarsanız, 1'i çıkardığınızda, yüksek dereceli biti, biraz kaybolmuş olmalı.
Ocak'ta migle

29

Onun kullanışlı bit karıştırma özelliklerine rağmen, XOR olduğu değil değişebilirliği nedeniyle karmaları birleştirmenin iyi bir yolu . {1, 2,…, 10} permütasyonlarını 10'luk bir karma tabloda saklarsanız ne olacağını düşünün.

Bir çok daha iyi bir seçimdir m * H(A) + H(B), burada m büyük bir tek sayıdır.

Kredi: Yukarıdaki birleştirici Bob Jenkins tarafından bir ipucu oldu.


2
Bazen değişebilirlik iyi bir şeydir, ancak xor o zaman bile berbat bir seçimdir, çünkü eşleşen tüm çiftler sıfıra eşitlenir. Aritmetik bir toplam daha iyidir; bir çift eşleşen öğenin karması 32 yerine yalnızca 31 bit yararlı veri tutacaktır, ancak bu sıfır tutmamaktan çok daha iyidir. Başka bir seçenek, aritmetik toplamı a olarak hesaplamak longve daha sonra üst kısmı alt kısım ile geri itmek olabilir.
supercat

1
m = 3aslında birçok sistemde iyi bir seçim ve çok hızlı. Not herhangi garip için mtamsayı çarpma modülo olduğu 2^32ya 2^64ve herhangi bit kaybetme değiliz bu nedenle ters çevrilebilir olduğunu.
StefanKarpinski

MaxInt'ın ötesine geçtiğinizde ne olur?
yıkıcı

2
herhangi bir tek sayı yerine bir asal seçmelisiniz
TermoTux

2
@ Karmaları birleştirirken gerekli olmayan infinum.
Marcelo Cantos

17

Xor, karmaları birleştirmenin "varsayılan" yolu olabilir, ancak Greg Hewgill'in yanıtı neden tuzaklarına sahip olduğunu da gösterir: İki özdeş karma değerinin xoru sıfırdır. Gerçek hayatta, aynı hashler birinin beklediğinden daha yaygındır. Daha sonra bu (çok seyrek olmayan) köşe durumlarda, ortaya çıkan birleşik karmaların her zaman aynı (sıfır) olduğunu görebilirsiniz. Karma çarpışmalar beklediğinizden çok, çok daha sık olurdu.

Çağdaş bir örnekte, yönettiğiniz farklı web sitelerinden kullanıcıların karma şifrelerini birleştiriyor olabilirsiniz. Ne yazık ki, çok sayıda kullanıcı şifrelerini tekrar kullanıyor ve ortaya çıkan karmaların şaşırtıcı bir oranı sıfır!


Umarım uydurulmuş örnek asla olmaz, şifreler tuzlanır.
user60561

8

Bu sayfayı bulan başkaları için açıkça belirtmek istediğim bir şey var. VE ve VEYA BlueRaja gibi çıktıları kısıtla - Danny Pflughoe dikkat çekmeye çalışıyor, ancak daha iyi tanımlanabilir:

Önce bunu açıklamak için kullanacağım iki basit işlevi tanımlamak istiyorum: Min () ve Max ().

Min (A, B), A ve B arasında daha küçük olan değeri döndürür, örneğin: Min (1, 5) 1 değerini döndürür.

Maks (A, B), A ve B arasında daha büyük olan değeri döndürür, örneğin: Maks (1, 5) 5 değerini döndürür.

Size verilirse: C = A AND B

Sonra bunu bulabilirsiniz C <= Min(A, B) bildiğimizi anlayabilirsiniz çünkü yapabileceğiniz hiçbir şey yoktur VE A veya B'nin 0 bitleri ile 1s yapmak için. Yani her sıfır bit sıfır bit kalır ve her bit sıfır bit olma şansına sahiptir (ve dolayısıyla daha küçük bir değer).

İle: C = A OR B

Bunun tersi doğrudur: C >= Max(A, B)Bununla AND fonksiyonunun sonucunu görüyoruz. Zaten bir olan herhangi bir bit sıfır olmak için ORED olamaz, bu yüzden bir kalır, ancak her sıfır bitin bir olma şansı vardır ve bu nedenle daha büyük bir sayı.

Bu, giriş durumunun çıktıya kısıtlamalar uyguladığı anlamına gelir. Eğer VE ile 90 olan herhangi bir şey varsa, diğer değer ne olursa olsun çıktının 90'a eşit veya daha az olacağını bilirsiniz.

XOR için, girdilere dayalı herhangi bir zımni kısıtlama yoktur. 255 ile bir bayt ters çevirirseniz, ancak olası herhangi bir baytın çıktı alınabileceğini bulabileceğiniz özel durumlar vardır. Her bit, diğer işlenendeki aynı bite bağlı olarak durumu değiştirme şansına sahiptir.


6
Bir söyleyebiliriz ORolan bitsel max ve ANDbir bit düzeyinde dk .
Paŭlo Ebermann

Çok iyi ifade etti Paulo Ebermann. Kripto'nun yanı sıra sizi burada görmek güzel.
Corey Ogburn

Şifreleme etiketli her şeyi içeren bir filtre oluşturdum , eski sorularla da değişti. Bu şekilde cevabınızı burada buldum.
Paŭlo Ebermann

3

XORTaraflı bir girişe sahip rastgele bir giriş yaparsanız , çıkış rastgele olur. Aynı şey ANDveya için de geçerli değildir OR. Misal:

00101001 XOR 00000000 = 00101001
00101001 VE 00000000 = 00000000
00101001 VEYA 11111111 = 11111111

@Greg Hewgill'in bahsettiği gibi, her iki giriş rastgele olsa bile , ANDveya kullanarak ORönyargılı çıktı elde edilir.

XORDaha karmaşık bir şey üzerinde kullanmamızın nedeni , buna gerek yok: XORmükemmel çalışıyor ve inanılmaz derecede aptalca hızlı.


1

Sol 2 sütunu örtün ve girdilerin sadece çıktıyı ne kullandığını bulmaya çalışın.

 a | b | a AND b
---+---+--------
 0 | 0 |    0
 0 | 1 |    0
 1 | 0 |    0
 1 | 1 |    1

Bir 1-bit gördüğünüzde, her iki girişin de 1 olduğunu bulmuş olmalısınız.

Şimdi XOR için de aynısını yapın

 a | b | a XOR b
---+---+--------
 0 | 0 |    0
 0 | 1 |    1
 1 | 0 |    1
 1 | 1 |    0

XOR girdiler hakkında hiçbir şey vermez.


0

Java.util.ArrayshashCode() içindeki çeşitli sürümler için kaynak kodu sağlam, genel kullanım karma algoritmaları için mükemmel bir referanstır. Kolayca anlaşılır ve diğer programlama dillerine çevrilir.

Kabaca söylemek gerekirse, çok özellikli hashCode()uygulamaların çoğu şu modeli izler:

public static int hashCode(Object a[]) {
    if (a == null)
        return 0;

    int result = 1;

    for (Object element : a)
        result = 31 * result + (element == null ? 0 : element.hashCode());

    return result;
}

Arkasındaki sihir 31ve Java kodunun neden bu kadar sık ​​kullandığı hakkında daha fazla bilgi için diğer StackOverflow Soru ve Cevaplarını arayabilirsiniz . Kusurlu değil, ancak genel performans özellikleri çok iyi.


2
Java'nın varsayılan "31 ile çarp ve topla / biriktir" karması çarpışmalarla yüklenir (örneğin string, string + "AA"IIRC ile çarpışan ) ve uzun zaman önce bu algoritmada spesifikasyonda pişirilmemelerini dilediler. Bununla birlikte, daha fazla bit ayarlanmış daha büyük bir tek sayı kullanmak ve bir kaydırma veya döndürme eklemek bu sorunu giderir. MurmurHash3'ün 'karışımı' bunu yapar.
Scott Carey

0

XOR bazen OR ve AND gibi bazı girişleri yok saymaz .

Örneğin AND (X, Y) alırsanız ve X girişini false ile beslerseniz, Y girişi önemli değildir ... ve muhtemelen karmaları birleştirirken girdinin önemli olmasını ister.

Eğer alırsan XOR (X, Y) sonra İKİ girdileri DAİMA olsun. Y'nin önemli olmadığı yerlerde X'in değeri olmazdı. X veya Y değiştirilirse çıkış bunu yansıtacaktır.

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.