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

Is

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

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

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

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

Word относится к типу String

EDIT: забыл сказать, что лучше реализовать в программе, вариант 1 или вариант 2?


person Hendrik Breezy    schedule 29.09.2016    source источник
comment
Поскольку хэш-коды не требуются и не могут быть уникальными, ответ на ваш вопрос — да, в том смысле, что обе реализации создают неуникальные хеш-коды.   -  person Sergey Kalinichenko    schedule 29.09.2016
comment
Любые столкновения с Word.GetHashCode() по-прежнему будут сталкиваться после умножения на 7. Также приведение не имеет смысла.   -  person juharr    schedule 29.09.2016
comment
Расширяя комментарий juharr, если World.GetHashCode() дает 6 для worldA и worldB, то World.GetHashCode() * 7 дает 42 как для worldA, так и для worldB...   -  person D. Ben Knoble    schedule 29.09.2016
comment
Что ты конкретно имеешь ввиду? если вы получите два разных уникальных результата для двух слов в первом, вы получите два разных уникальных результата из второго. Точно так же, если вы получите два идентичных результата из двух слов в первом, то второе также даст два идентичных результата. Это кажется несколько очевидным при взгляде на код, поэтому кажется, что у вас есть что-то большее, чем это, что, я думаю, могло бы быть связано с проработкой.   -  person Chris    schedule 29.09.2016
comment
Действительно ли (3 * 7) == (3 * 7) совпадает с 3 == 3?   -  person 15ee8f99-57ff-4f92-890c-b56153    schedule 29.09.2016
comment
@Chris Довольно просто доказать, что идентичные результаты останутся идентичными. Намного менее тривиально доказать, имеют ли разные результаты повышенную вероятность столкновения со вторым подходом (если вы также выполняете операцию unchecked). Подробности смотрите в ответе Даса.   -  person Servy    schedule 29.09.2016
comment
@Servy: Верно, я думаю. У меня математическое образование, поэтому я забываю, что очевидное для меня может быть неочевидным для других. :)   -  person Chris    schedule 29.09.2016
comment
@Chris Нет, ты сказал, что очевидно, что равные результаты останутся равными. Это не самая сложная часть. Трудная часть - определить, остаются ли разные значения разными. На самом деле это нетривиальное доказательство.   -  person Servy    schedule 29.09.2016


Ответы (2)


Понятно, что любые коллизии в реализации 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) & (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 по модулю 216 и проверяет, что каждое число из диапазона создается ровно один раз.

Count of duplicate mappings found: 0

Демо.

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

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

Нет никакой разницы.

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

person Sergey Kalinichenko    schedule 29.09.2016
comment
Да, я забыл сказать, что номер пима был нарочно. Так какой из них лучше вариант А или Б? - person Hendrik Breezy; 29.09.2016
comment
Поскольку это устанавливает, что разницы нет, используйте более простой вариант. - person stuartd; 29.09.2016
comment
@HendrikBreezy Поскольку .NET осторожно использует подсчет простых сегментов, нет никакой разницы. - person Sergey Kalinichenko; 29.09.2016

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

person Servy    schedule 29.09.2016
comment
Глядя на msdn.microsoft.com/en-gb/library/a569z7k8.aspx он говорит, что выражения, содержащие непостоянные термины, не проверяются по умолчанию во время компиляции и во время выполнения, так что не означает ли это, что они будут непроверены, если не проверены явно? Я признаю, что на самом деле я не играл ни с чем, где мне нужно было беспокоиться о проверенных/непроверенных, поэтому я вполне могу ошибаться... - person Chris; 29.09.2016
comment
Компилятор @Chris C# и VS по умолчанию не отмечены. - person Cory Nelson; 29.09.2016