Почему 5-битный сдвиг влево в хэш-функции?

Популярный ответ на создание хэш-функции в JS приведен в Simple (небезопасный ) хэш-функция для JavaScript? и Создать хэш из строки в Javascript

Один из примеров кода:

String.prototype.hashCode = function() {
    var hash = 0;
    if (this.length == 0) {
        return hash;
    }
    for (var i = 0; i < this.length; i++) {
        var char = this.charCodeAt(i);
        hash = ((hash<<5)-hash)+char;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
}

Одна строка, которая не имеет для меня смысла, это hash = ((hash<<5)-hash)+char;

Может кто-нибудь объяснить, ПОЧЕМУ это делается? Насколько я понимаю, мы делаем 5 bit left shift с хэшем. Есть ли причина, почему это 5 бит, а не 4 или 6? Кроме того, почему мы тогда минус хеш и добавить char?


person TomDane    schedule 22.08.2018    source источник
comment
Почти уверен, что это не имеет значения - это просто пример одного из способов преобразования строки символов в хэш. Вы можете использовать любой алгоритм, который вам нравится, используя любые сдвиги, добавления, вычитания и т. д., которые вам нравятся.   -  person CertainPerformance    schedule 22.08.2018


Ответы (1)


(hash << 5) равно (hash * 32), поэтому ((hash << 5) - hash) равно (hash * 31). А причина умножения на 31 описана в ответах на вопрос Почему функция Java hashCode() в String использует 31 в качестве множителя?

Итак, если это изменить на (hash * 31), результат будет таким же. Возможно, (hash << 5) - hash немного быстрее, так как сдвиг/вычитание может быть быстрее, чем умножение. Однако, если это действительно так, зависит от многих факторов (используется ли JIT-компиляция, и оптимизации в JIT, и даже от процессора). Поэтому я предполагаю, что автор кода протестировал его и обнаружил, что в его случае он работает быстрее.

person Thomas Mueller    schedule 22.08.2018
comment
Другой ответ, который помог мне понять, это crypto.stackexchange.com/a/8534. В частности, битовые сдвиги так широко используются, потому что они способствуют хорошей диффузии. - person TomDane; 23.08.2018
comment
Да и умножение на 31 это в основном два битовых сдвига (на 5 и на 1) и вычитание. Даже если подумать, другие алгоритмы хэширования, такие как Murmur, имеют лучший эффект диффузии/путаницы/лавины. - person Thomas Mueller; 23.08.2018