Я ищу реализовать быструю, хорошо распределенную хэш-таблицу в C #. У меня возникают проблемы с выбором моей функции ограничения хеша, которая берет произвольный хеш-код и «ограничивает» его, чтобы его можно было использовать для индексации сегментов. Пока я вижу два варианта:
С одной стороны, вы можете убедиться, что в ваших корзинах всегда есть простое число элементов, и чтобы ограничить хеш, вы просто модулируете его по количеству блоков. Это, собственно, то, что делает словарь .NET . Проблема с этим подходом состоит в том, что использование% является чрезвычайно медленным по сравнению с другими операциями; если вы посмотрите на столах инструкции Agner Противотуманной ,
idiv
(который является ассемблерным кодом , который получает генерируется для%) имеет задержку выполнения команд ~ 25 циклов для новых процессоров Intel. Сравните это около 3 дляmul
, или 1 для битового опса , какand
,or
илиxor
.С другой стороны, у вас может быть число блоков, равное степени 2. Вам все равно придется вычислять модуль хэша, чтобы не пытаться индексировать вне массива, но на этот раз это будет дешевле , Поскольку для степеней 2
% N
справедливо& (N - 1)
, ограничение сводится к операции маскирования, которая занимает всего 1-2 цикла. Это сделано с помощью Google sparsehash . Недостатком этого является то, что мы рассчитываем на то, что пользователи будут предоставлять хорошие хэши; Маскировка хеша фактически обрезает часть хеша, поэтому мы больше не учитываем все биты хеша. Если хеш пользователя распределен неравномерно, например, заполнены только старшие биты или младшие биты постоянно одинаковы, тогда этот подход имеет гораздо более высокую частоту коллизий.
Я ищу алгоритм, который я могу использовать, который имеет лучшее из обоих миров: он учитывает все биты хэша, а также быстрее, чем использование%. Это не обязательно должен быть модуль, просто что-то, что гарантированно находится в диапазоне 0..N-1
(где N - длина сегментов) и имеет равномерное распределение для всех слотов. Существует ли такой алгоритм?
Спасибо за помощь.
источник
(2^N +/- 1)
см stackoverflow.com/questions/763137/...Ответы:
Современные реализации хеш-таблиц не используют функцию по модулю. Они часто используют мощность таблиц двух размеров и отсекают ненужные биты. Идеальная хеш-функция позволила бы это. Использование модуля по модулю в сочетании с размерами таблицы простых чисел возникло в те дни, когда хеш-функции были в целом плохими, поскольку они часто находятся в разработке .net. Я рекомендую прочитать о SipHash , современной хеш-функции, а затем прочитать о некоторых других современных функциях, таких как xxHash .
Я должен объяснить, почему хэш-функции .net часто бывают плохими. В .net программисты часто вынуждены реализовывать хеш-функции, переопределяя GetHashcode. Но .net не предоставляет инструментов, необходимых для обеспечения высокого качества созданных программистом функций, а именно:
Для получения дополнительной информации об использовании результата хеш-функции в качестве индекса хеш-таблицы см. Определения универсальных форм хеширования в этой статье: Более быстрое 64-битное универсальное хеширование с использованием умножений без переноса
источник
Чтобы использовать AND, сохраняя все биты, используйте также XOR.
Для примера
temp = (hash & 0xFFFF) ^ ( hash >> 16); index = (temp & 0xFF) ^ (temp >> 8);
.Для этого примера нет модуля по модулю и все 32 бита
hash
эффекта 8-битныеindex
. Однако, зависит ли это от DIV или нет, это зависит от слишком многих факторов, и в некоторых случаях он может быть медленнее, чем DIV (например, большой хэш и крошечный индекс).источник
index
будет в диапазоне[0..255]
. Мне нужно что-то в диапазоне[0..n-1]
, гдеn
находится количество ведер.Вы можете воспользоваться тем фактом, что многие простые целые числа имеют модульное мультипликативное обратное значение. Смотрите эту статью . Вы выполнили одно из ограничений, сделав свой индекс корзины простым и модуль 2 ^ n, который по своей природе относительно простой.
В статье описывается алгоритм поиска такого числа, при котором умножение на это число и игнорирование переполнения приведут к тому же результату, что и при делении на размер индекса сегмента.
источник