Самый быстрый генератор хэш-кода .NET

Я реализую собственный GetHashCode для класса System.Drawing.Point на С#. Мой метод в настоящее время не соответствует следующему требованию:

var hashA = MyGetHashCode(new Point(1, 0));
var hashB = MyGetHashCode(new Point(0, 1));
var hashC = MyGetHashCode(new Point(0, 0));
var hashD = MyGetHashCode(new Point(1, 1));
Assert.AreNotEqual(hashA ^ hashB, hashC ^ hashD);

Чтобы пройти этот тест, я уверен, что подойдет использование new SHA256Managed().ComputeHash(currentHash). Но есть ли другой более быстрый алгоритм хеширования? Я знаю, что SHA256 — это безопасность, а мне это не нужно.


person Jader Dias    schedule 08.06.2009    source источник
comment
Как вы пришли к мысли, что ваша хеш-функция должна пройти этот тест?   -  person mqp    schedule 08.06.2009
comment
@mquander Конечно, это кажется странным. Но некоторые другие функции класса Equals основаны на простой реализации GetHashCode, которая, в свою очередь, опирается на мой пользовательский метод Point.GetHashCode.   -  person Jader Dias    schedule 08.06.2009
comment
@mquander Все дело в том, чтобы не повторять код в Equals и GetHashCode и делать их эквивалентными.   -  person Jader Dias    schedule 08.06.2009


Ответы (7)


Простой хэш? как насчет чего-то вроде:

 (17 * point.X) + (23 * point.Y);

Или для более очевидной энтропии:

int hash = -1047578147;
hash = (hash * -1521134295) + point.X;
hash = (hash * -1521134295) + point.Y;

(числа из кода анонимного типа C#)

person Marc Gravell    schedule 08.06.2009
comment
Марк, это, безусловно, выполнит Assert, но не ограничено (большие X или Y будут переполнены)... если вы разрешите переполнение, то у него не будет хорошего распределения. - person Jorge Córdoba; 08.06.2009
comment
Он будет обернут (не отмечен); дистрибутив, AFAIK, в порядке... Это подход, используемый компилятором C #; -p - person Marc Gravell; 08.06.2009
comment
Эти числа являются (как указано) просто числами, которые компилятор C# будет использовать для анонимного типа формы: new {X = 123, Y = 456} - person Marc Gravell; 08.06.2009

  • Почему вы это делаете? Наверняка у System.Drawing.Point уже есть хорошая функция хеширования?

  • Вы же понимаете, что тест не является строгим требованием? Хэш-коды не обязательно должны быть уникальными.

  • Если вам действительно нужен действительно хороший хэш рассматриваемых координат, вы можете начать с эта страница о хешировании нескольких целых чисел.

person mqp    schedule 08.06.2009
comment
Улучшите функцию хеширования - x ^ y... это не очень хорошо; это означает, что все, что находится на диагонали, равно нулю, а все, что симметрично, т.е. (5,7) и (7,5) - равно. - person Marc Gravell; 08.06.2009
comment
Это не очень хорошо, но если у вас нет довольно патологического распределения баллов, это нормально. У меня такое ощущение, что ОП не выполняет никаких конкретных требований к производительности, если он рассматривает возможность использования хэша SHA, поэтому я сомневаюсь, что требуется что-то лучшее. - person mqp; 08.06.2009
comment
На первый вопрос я ответил в комментариях к вопросу. - person Jader Dias; 08.06.2009

Я знаю, что это не ответ на ваш вопрос, но я должен упомянуть для других читателей, что вы меняете поведение по умолчанию встроенного метода фреймворка. Согласно документации:
http://msdn.microsoft.com/en-us/library/system.object.getashcode.aspx

Реализация метода GetHashCode по умолчанию не гарантирует уникальных возвращаемых значений для разных объектов. Кроме того, .NET Framework не гарантирует реализацию метода GetHashCode по умолчанию, и возвращаемое им значение будет одинаковым в разных версиях .NET Framework. Следовательно, реализация этого метода по умолчанию не должна использоваться в качестве уникального идентификатора объекта для целей хеширования.

person Joel Martinez    schedule 08.06.2009
comment
Не могли бы вы использовать цитату, а не блок кода (поставьте перед цитатой символ › вместо отступа)? Это значительно облегчит чтение. - person Samir Talwar; 08.06.2009
comment
Это не проблема в данном случае. Они означают, что вы не должны использовать GetHashcode по умолчанию в качестве уникального значения, потому что разные объекты могут возвращать один и тот же хэш. Когда Jader реализует его как (практически) уникальное значение (используя sha256 или что-то еще), он ничего не сломает. Просто будет медленно... - person tanascius; 08.06.2009
comment
Честно говоря, это будет довольно медленно, если у него на самом деле есть большая хеш-таблица точек — достаточно медленно, чтобы это было довольно смешно. - person mqp; 08.06.2009
comment
Да, конечно - это не очень умно, и он никогда не должен использовать sha256 или что-то подобное для этой цели. Но утверждение Джоэла, тем не менее, неверно. - person tanascius; 08.06.2009

Вот интересная статья о скорости хеширования:

Хеш-функция для поиска в хэш-таблице

person TWA    schedule 08.06.2009

Простая реализация хэша Elf (это в delphi, его легко перевести)

function ElfHash(id : string; tableSize : integer) : integer;
var
  i : integer;
  h,x : longint;
begin
  h := 0;
  // Obtener el valor numérico
  for i := 1 to Length(id) do
  begin
    h := (h shl 4) + Ord(id[i]);

    x := h and $F0000000;
    if x <;>; 0 then
       h = h xor (x shr 24) xor x;
  end;
  // Ajustar al tamaño de la tabla
  result := h mod tableSize;
end;
person Jorge Córdoba    schedule 08.06.2009
comment
Я думал, что знаю delphi, но понятия не имею, что такое ‹;›; означает - person Jader Dias; 18.06.2009
comment
:) Поговорите с кодом дезинфицирующего средства stackoverflow... Это очевидно ‹› - person Jorge Córdoba; 18.06.2009
comment
Говорит «Легко перевести» при запросе на сдвиг влево, сдвиг вправо и эксклюзивный или в управляемом коде. - person Hogan; 14.08.2013

Я не знаю, какое у вас приложение, но, возможно, вы ищете хеширование Zobrist.

http://en.wikipedia.org/wiki/Zobrist_hashing

Его можно обновлять постепенно, что делает его очень быстрым.

person Fantius    schedule 08.06.2009

Если вы заранее знаете, что значение вашей точки находится между 0 и N, вы можете использовать hashcode = X+Y*N; Это довольно очевидный возможный хэш. Это вовсе не случайно, имеет уродливое повторение и, как правило, довольно глупо. Это эквивалентно соединению битов ваших двух точек, предполагая, что N является степенью числа 2. И у него идеальное равномерное распределение и нет коллизий.

Я использовал эту стратегию с отличным эффектом в прошлом, но признаю, что у нее есть некоторые реальные (но очевидные) ограничения. Самым большим из них является то, что происходит, когда N достаточно велико, чтобы N ^ 2 не вписывалось в ваше хеш-значение (т.е. болезненные коллизии.

person Brian    schedule 08.06.2009
comment
Моя текущая реализация ((x ‹‹ 16) | (x ›› 16)) ^ y (на C#), которая подходит под ваше описание - person Jader Dias; 08.06.2009