В чем преимущество применения сложной хеш-функции и последующего использования mod n вместо простого mod n для ввода? - PullRequest
1 голос
/ 22 мая 2019

При хешировании мы берем входные данные и применяем некоторый сложный алгоритм хеширования. Затем мы делаем мод n, чтобы найти корзину или сервер, на который необходимо отправить эти входные данные. Хеш-ввод x -> Hash (x) -> Делить на n -> Hash (x) mod n указывает местоположение сегмента.

Если мы берем входные данные напрямую без хэширования, это эквивалентно наличию хэш-функции для идентификации. Hash (x) = x .. mod n..Википедия называет эту функцию «тривиальной» хеш-функцией.

Обычно hash (x) - это сложный алгоритм хеширования, такой как MD5, SHA и т. Д. Q1) Независимо от того, как мы его хэшируем, оно просто сводится к значению от 0 до n-1 (напоминание при делении на n). Итак, как же важен выбор хеш-функции? Q2) Я знаю, что идеальная хеш-функция распределяет входные значения равномерно по сегментам. В этом аспекте эти сложные функции хеширования превосходят функцию идентификации хеша?

Предположим, что входные данные всегда являются целыми числами.

1 Ответ

1 голос
/ 22 мая 2019

В чем преимущество применения сложной хеш-функции и последующего использования mod n вместо простого ввода mod n для ввода?

Давайте посмотрим на простой пример. Скажем, наши ключи - это 100 указателей на некоторые объекты в памяти, которые выровнены по 8 байтов: это означает, что 3 младших бита всегда равны 0. Наш размер таблицы в настоящее время составляет 128 ведер. Перед тем как хэшировать, мы изменили значения указателя на 128, поэтому получаем:

 32-bit pointer bits   xxxxxxxx xxxxxxxx xxxxxxxx xxxxx000
             mod 128   00000000 00000000 00000000 0xxxx000

Обратите внимание, что только 4 потенциально значимых бита из указателя попадают в нашу хеш-функцию, что означает, что не более 16 различных значений достигают хеш-функции: наши 100 указателей будут сталкиваться только в 16 сегментах, что означает, что цепочки столкновений обычно имеют глубину 7 или 8 даже для самой сильной хэш-функции. Это печально, учитывая, что у нас было 128 сегментов для 100 ключей: у нас должно было быть в основном 0, 1 или 2 ключа, сопоставленных с любым конкретным сегментом.

Теперь, что бы произошло, если бы у нас было 100 указателей на области отображения памяти, каждая из которых была выровнена по 4096-байтовой странице? Все они были бы привязаны к одному и тому же ведру.

Не выполнение операции мода до конца гарантирует, что биты старшего разряда в ключах могут помочь рандомизировать позиции битов младшего разряда в хеш-значении, и эти биты младшего разряда могут повлиять на область, в которую преобразуется ключ. (Еще одна вещь, которая может немного помочь, это убедиться, что размер таблицы - это простое число, но лучше всего его использовать в сочетании с выполнением мода после хэширования. В качестве случайной выборки компилятор GNU C ++ использует счетчики простых сегментов для хеш-таблиц стандартной библиотеки, в то время как Visual C ++ использует степень двойки (и для длинных строк быстрее, но более слабые хеш-функции))

Q1) Независимо от того, как мы его хэшируем, оно просто сводится к значению от 0 до n-1 (напоминание при делении на n). Итак, как же важен выбор хеш-функции?

Очевидно, что если бы наша хеш-функция была h(key) { return 0 }, то каждый ключ сталкивался бы в сегменте 0. С другой стороны, криптографическая хеш-функция должна эффективно случайным образом, но многократно отображать любой данный ключ в данный сегмент, так что любой бит изменяется в любом месте ключа создается полностью некоррелированное отображение. Это помогает защитить вас от чрезмерных столкновений с ключами, которые не меняются во многих битовых позициях. Но сильные хеш-функции, как правило, требуют больше времени для вычисления, и уменьшение коллизий может или не может привести к выигрышу в чистой производительности. Иногда стоит выбирать силу хэш-функции, основываясь на знании того, насколько ключи могут отличаться друг от друга.

Q2) Я знаю, что идеальная хеш-функция распределяет входные значения равномерно по сегментам. В этом аспекте эти сложные функции хеширования превосходят функцию идентификации хеша?

В крайнем случае хеш-функции идентичности надеются, что входные числа будут отображаться в отдельные сегменты с большей вероятностью, чем хеш-функция криптографической стойкости: например, если мы хешируем 5, 6, 7, 8, 10 в таблицу, используя это тождественная функция, они плотные (близкие друг к другу) и охватывают всего 6 значений (от 5 до 10), поэтому до тех пор, пока размер таблицы> = 6 (например, простое значение 7), они гарантированно не столкнутся. Но хэш-функции идентичности с учетом склонных к коллизиям входов (например, указатели, приведенные к числам) являются катастрофой, поскольку они ничего не сделали, чтобы смешать более значимые биты с менее значимыми битами до того, как включится мод - та же проблема, что и для указателей выше.

В общем, хэш-функции идентичности могут иметь лучшую производительность в среднем случае для общих целочисленных ключей, но гораздо хуже в худшем случае для неплотных, не случайных / склонных к коллизиям ключей.

...