xoradalah fungsi default berbahaya untuk digunakan saat hashing. Itu lebih baik daripada anddan or, tapi itu tidak banyak bicara.
xorsimetris, sehingga urutan unsur-unsurnya hilang. Jadi "bad"hash akan menggabungkan sama dengan "dab".
xor memetakan nilai identik berpasangan ke nol, dan Anda harus menghindari pemetaan nilai "umum" ke nol:
Jadi (a,a)dipetakan ke 0, dan (b,b)juga dipetakan ke 0. Karena pasangan seperti itu hampir selalu lebih umum daripada keacakan mungkin menyiratkan, Anda berakhir dengan banyak tabrakan jauh di nol dari yang seharusnya.
Dengan dua masalah ini, xorakhirnya menjadi hash combiner yang terlihat setengah layak di permukaan, tetapi tidak setelah pemeriksaan lebih lanjut.
Pada perangkat keras modern, menambahkan biasanya sekitar secepat xor(mungkin menggunakan lebih banyak daya untuk melakukan ini, diakui). Menambahkan tabel kebenaran mirip dengan xorpada bit yang dimaksud, tetapi juga mengirimkan sedikit ke bit berikutnya ketika kedua nilai adalah 1. Ini berarti ia menghapus lebih sedikit informasi.
Jadi hash(a) + hash(b)lebih baik daripada hash(a) xor hash(b)jika a==b, hasilnya hash(a)<<1bukan 0.
Ini tetap simetris; jadi "bad"dan"dab" mendapatkan hasil yang sama tetap menjadi masalah. Kami dapat memutus simetri ini dengan biaya sederhana:
hash(a)<<1 + hash(a) + hash(b)
alias hash(a)*3 + hash(b) . (menghitung hash(a)sekali dan menyimpan disarankan jika Anda menggunakan solusi shift). Konstanta ganjil mana pun alih-alih 3secara bijektif akan memetakan kbilangan bulat tak bertanda "-bit" ke dirinya sendiri, karena peta bilangan bulat tak bertanda adalah modulo matematika 2^kuntuk beberapak , dan konstanta ganjil apa pun relatif utama 2^k.
Untuk versi yang lebih keren, kita dapat memeriksa boost::hash_combine, yang secara efektif:
size_t hash_combine( size_t lhs, size_t rhs ) {
lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2);
return lhs;
}
di sini kami menambahkan bersama beberapa versi bergeser dari seed dengan konstanta (yang pada dasarnya acak 0s dan 1s - khususnya itu adalah kebalikan dari rasio emas sebagai fraksi titik tetap 32 bit) dengan beberapa tambahan dan xor. Ini memecah simetri, dan memperkenalkan beberapa "noise" jika nilai hash yang masuk buruk (yaitu, bayangkan setiap komponen hash ke 0 - di atas menanganinya dengan baik, menghasilkan noda 1dan0 s setelah masing-masing digabungkan. Naif saya 3*hash(a)+hash(b)hanya menghasilkan a 0di kasus itu).
(Bagi mereka yang tidak terbiasa dengan C / C ++, a size_t adalah nilai integer yang tidak ditandatangani yang cukup besar untuk menggambarkan ukuran objek apa pun dalam memori. Pada sistem 64 bit, biasanya integer 64 bit yang tidak ditandai. Pada sistem 32 bit , bilangan bulat 32 bit unsigned.)