xor
- це небезпечна за замовчуванням функція, яка використовується при хешировании. Це краще, ніж and
і or
, але це не дуже говорить.
xor
симетричний, тому порядок елементів втрачається. Тож "bad"
хеш-комбінат буде таким же, як і "dab"
.
xor
відображає попарно однакові значення до нуля, і вам слід уникати відображення "загальних" значень до нуля:
Отже, (a,a)
відображається на 0, а (b,b)
також відображається на 0. Оскільки такі пари майже завжди зустрічаються частіше, ніж це може означати випадковість, у вас виникає набагато більше зіткнень у нулі, ніж слід.
З цими двома проблемами, в xor
кінцевому підсумку це хеш-комбайнер, який виглядає наполовину пристойно на поверхні, але не після подальшого огляду.
На сучасне обладнання, додавання зазвичай приблизно так само швидко xor
(мабуть, мабуть, використовується більше енергії, щоб зняти це, правда,). Додавання таблиці істинності схоже xor
на відповідний біт, але воно також надсилає трохи до наступного біта, коли обидва значення дорівнюють 1. Це означає, що він стирає менше інформації.
Так що hash(a) + hash(b)
краще, ніж hash(a) xor hash(b)
у тому випадку a==b
, якщо результат hash(a)<<1
замість 0.
Це залишається симетричним; тож "bad"
і "dab"
отримання однакового результату залишається проблемою. Ми можемо порушити цю симетрію за невелику вартість:
hash(a)<<1 + hash(a) + hash(b)
ака hash(a)*3 + hash(b)
. ( hash(a)
один раз підрахунок і зберігання рекомендується, якщо ви використовуєте рішення зсуву). Будь-яка непарна константа замість 3
бієктивно буде відображати " k
-бітове" непідписане ціле число до себе, оскільки карта на непідписані цілі числа є математичним модулем 2^k
для деяких k
, а будь-яка непарна константа є відносно простою 2^k
.
Для рівномірнішої версії ми можемо вивчити boost::hash_combine
, що ефективно:
size_t hash_combine( size_t lhs, size_t rhs ) {
lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2);
return lhs;
}
тут ми додаємо кілька зміщених версій seed
з константою (що в основному є випадковими 0
s і 1
s - зокрема, це обернено золотого відношення як 32-бітна частка з фіксованою точкою) з деяким додаванням і xor. Це порушує симетрію, і вводить деякі «шум» , якщо входять Hashed значення є бідними (тобто, уявіть собі , кожен компонент хеші 0 - вищевказані ручки це добре, створюючи мазок 1
і 0
. S після кожного помошью наївним 3*hash(a)+hash(b)
просто виводить 0
ін той випадок).
(Для тих, хто не знайомий з C / C ++, a size_t
- ціле цільове значення без підпису, яке є достатньо великим, щоб описати розмір будь-якого об'єкта в пам'яті. У 64-бітовій системі зазвичай це 64-бітове безпідписане ціле число. У 32-бітовій системі , 32-бітове ціле число без підпису.)