Реализация C # GetHashCode

#c# #gethashcode #hash-code-uniqueness

#c# #gethashcode #уникальность хэш-кода

Вопрос:

Является

 public override int GetHashCode()
{
    return Word.GetHashCode();
}
  

Действительно то же самое для

 public override int GetHashCode()
{
    return (int) Word.GetHashCode() * 7;
}
  

что касается уникальности?

Word имеет тип String

РЕДАКТИРОВАТЬ: я забыл сказать, какой из них лучше реализовать в программе, вариант 1 или 2?

Комментарии:

1. Поскольку хэш-коды не являются обязательными и не могут быть уникальными, ответ на ваш вопрос «да» в том смысле, что обе реализации создают неуникальные хэш-коды.

2. Любые столкновения с Word.GetHashCode() все равно будут сталкиваться после умножения на 7. Также приведение бессмысленно.

3. Расширяя комментарий Джухарра, if World.GetHashCode() выдает 6 для worldA и worldB, затем World.GetHashCode() * 7 выдает 42 для worldA и worldB…

4. Что именно вы имеете в виду? если вы получите два разных уникальных результата для двух слов в первом, вы получите два разных уникальных результата из второго. Аналогично, если вы получите два идентичных результата из двух слов в первом, то второе также даст два идентичных результата. Это кажется несколько очевидным при взгляде на код, хотя кажется, что для вас есть что-то большее, чем этот вопрос, который, я думаю, мог бы быть доработан.

5. (3 * 7) == (3 * 7) Действительно ли это то же 3 == 3 самое, что и ?

Ответ №1:

Понятно, что любые коллизии в Word.GetHashCode() реализации приведут к коллизии в (int) Word.GetHashCode() * 7 реализации, потому что умножение одинаковых чисел дает идентичные результаты.

Более интересный вопрос заключается в том, приведут ли непротиворечивые хэш-коды из первой реализации к коллизиям во второй реализации. Оказывается, что ответ «нет», потому что диапазон int и 7 являются взаимно простыми числами. Следовательно, умножение создает уникальное сопоставление после удаления переполнения.

Вы можете запустить небольшой тест с двухбайтовыми хэш-кодами, чтобы посмотреть, что произойдет:

 const int Max = 1<<16;
var count = new int[Max];
for (int i = 0 ; i != Max ; i  ) {
    count[(i * 7) amp; (Max-1)]  ;
}
var notOne = 0;
for (int i = 0 ; i != Max ; i  ) {
    if (count[i] != 1) {
        notOne  ;
    }
}
Console.WriteLine("Count of duplicate mappings found: {0}", notOne);
  

Эта программа сопоставляет i значение хэш-кода по 7 * i модулю 2 16 и проверяет, что каждое число из диапазона создается ровно один раз.

 Count of duplicate mappings found: 0
  

ДЕМОНСТРАЦИЯ.

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

какой из них лучше?

Разницы нет.

Примечание: Вышеизложенное предполагает, что вы игнорируете переполнение целых чисел.

Комментарии:

1. Да, я забыл сказать, что номер pime был указан специально. Итак, какой из них лучше вариант A или B?

2. Поскольку это показывает, что разницы нет, используйте более простой вариант.

3. @HendrikBreezy Поскольку .NET тщательно использует количество основных сегментов, разницы нет.

Ответ №2:

Поскольку вы не запускаете код в unchecked контексте, то последний будет генерировать исключение каждый раз, когда происходит переполнение, что достаточно вероятно (будет генерироваться 6/7 диапазона хэшей, поэтому обычно равномерно распределенный хэш-код имеет вероятность ~ 6/7 исключения).

Комментарии:

1. Глядя на msdn.microsoft.com/en-gb/library/a569z7k8.aspx в нем говорится, что «Выражения, содержащие непостоянные термины, по умолчанию не отмечены во время компиляции и выполнения», так не означает ли это, что они были бы сняты, если бы не были отмечены явно? Я признаю, что на самом деле я не играл ни с чем, где мне нужно было беспокоиться о checked / unchecked, поэтому я могу легко ошибаться…

2. @Chris Компилятор C # и VS по умолчанию не отмечены.