LINUX.ORG.RU

F# hash structured data

 


0

1

На поиск бага, вызванного фичей ниже, я потратил целый день, а теперь, пожалуйста, просто объясните мне эту магию:

> hash (1.0, 2.0);;
val it : int = 2112880640
> hash (2.0, 1.0);;
val it : int = 2146435072
> hash (1.0, 0.0);;
val it : int = 1039138816
> hash (0.0, 1.0);;
val it : int = 1072693248
> hash (2.0, 0.0);;
val it : int = 1073741824
> hash (0.0, 2.0);;
val it : int = 1073741824

Microsoft, сэр!

anonymous ()
Ответ на: комментарий от anonymous

F#, сэр, это не только MS. Да и вообще где ещё спрашивать, если не ЛОРе.

pseudo-cat ★★★ ()

а что не так? хеши в принципе своем обязаны совпадать у одинаковых объектов, но ничуть не обязаны различаться у разных.

arkhnchul ★★ ()
Ответ на: комментарий от anonymous

мсье, много найдете хешей, гарантирующих уникальность объекта (не являющегося int-ом или еще чем целочисленным)?

google://хеш коллизия

arkhnchul ★★ ()
Ответ на: комментарий от arkhnchul

sha256/512

Как найдёшь — обязательно сообщи.

anonymous ()
Ответ на: комментарий от arkhnchul

я думал, что hash не гарантирует уникальность пользовательских типов, т.к. реализация GetHashCode() может быть любой, хоть и возвращающей одно и тоже число каждый раз. Но для стандартных типов, GetHashCode() для одного типа во всяком случае, должна работать адекватно, иначе зачем она нужна. Другое дело, как работает GetHashCode для составных объектов - разбивает ли объект на отдельные и складывает или как-то по-другому? Но мне в общем-то похрен, я простой программист, увидел hash, применил.

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

Но для стандартных типов, GetHashCode() для одного типа во всяком случае, должна работать адекватно

так и работает. Еще раз: хеш не означает уникальности.

иначе зачем она нужна.

для реализации ассоциативных массивов тащемта например.

arkhnchul ★★ ()

Функция hash возвращает значения из множества, ограниченного количеством элементов 2^64. Это столько уникальных объектов можно отобразить на уникальные хеши. Теперь, как можно отобразить 2^1000 уникальных объекта на хеши без коллизий? Кто знает способ?

dave ★★★★★ ()
Ответ на: комментарий от dave

сделать хэш составным (i, hash) и разбить элементы на n групп, i>0 && i <=n?

pseudo-cat ★★★ ()

А у тебя миллионы хешей берутся?

Norgat ★★★★★ ()
Ответ на: комментарий от pseudo-cat

Так идея хеша в том, что мы нечто большое отображаем по быстрому на нечто маленькое, да так, чтобы разные элементы по возможности получали разные значения. Ключевые слова: «нечто маленькое» и «по возможности».

Но хеши для разных объектов могут совпадать из-за того, что хешей мало, а объектов - много.

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

Прошу извинить за некую тавтологию. Я чувствую, что у тебя нет математического образования) Поэтому как в американских учебниках немного перемусоливаю одно и тоже. Особенно в учебниках по экономике так любят писать, хотя в учебниках для программистов тоже встречается)

dave ★★★★★ ()
Последнее исправление: dave (всего исправлений: 1)
Ответ на: комментарий от dave

Да, я понял, но как-то не верится, что на таких простых данных возможна была на практике такая коллизия.

pseudo-cat ★★★ ()
Последнее исправление: pseudo-cat (всего исправлений: 1)
Ответ на: комментарий от Norgat

эм, нет, по сути у меня берётся максимум 10^3 хэшей, но разница то какая, когда в моём случае хэш (0,2) = хэш(2,0), а такие значения всегда есть в моём случае, т.к. эти пары - индексы матрицы.

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

А ты не думал просто перегонять их в строки и брать хеши от строк?

Norgat ★★★★★ ()
Ответ на: комментарий от Norgat

типа хеши строк уникальны.

тут вопрос - зачем оные хеши были применены?

arkhnchul ★★ ()
Ответ на: комментарий от pseudo-cat

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

Zenom ★★★ ()
Ответ на: комментарий от Norgat

Завтра сделаю что-нибудь с этим, возможно через строки.

pseudo-cat ★★★ ()
Ответ на: комментарий от Zenom

хэши нужны были чтобы складывать выборку по матрице в хэш таблицу

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

А, тьфу. Индексы матрицы.

i*columns + j, где i - номер строки, j - номер столбца. Вот и будет тебе хеш.

Norgat ★★★★★ ()
Последнее исправление: Norgat (всего исправлений: 1)
Ответ на: комментарий от pseudo-cat

Хэш-таблица помимо равенства хэшей проверяет равенство ключей. В чём тогда проблема с коллизиями?

Zenom ★★★ ()
Ответ на: комментарий от Norgat

матрица 3 x 3: hash [(1, 1)] = 4; hash [(0, 0); [1, 1]] = 4 ну и ещё варианты такие же есть) у меня хэш не от одной пары индексов а от списка. А насчет строк - хэш от строк разве уникальный?

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

Не верю, что в F# нет готовых хэш-таблиц с любыми хэшабельными типами ключей и авторазрешением коллизий.

Ivana ()
Ответ на: комментарий от pseudo-cat

Не надо так делать. Можно использовать сами пары (i, j), но не хэши.

Zenom ★★★ ()
Ответ на: комментарий от pseudo-cat

А насчет строк - хэш от строк разве уникальный?

Коллизии крайне редки. Тебе придётся постараться, чтобы напороться.

Norgat ★★★★★ ()
Ответ на: комментарий от Norgat

То есть коллизии со структуированными значениями, парами к примеру, намного чаще встречаются? Мне просто любопытно, это из-за складывания хэшей отдельных элементов?

pseudo-cat ★★★ ()
Ответ на: комментарий от Zenom

к примеру как? вся прелесть хэш таблиц в их быстром доступе. К примеру, если использовать множества вместо хэш таблиц то на моих примерах я получу разницу в 30 секунд работы против 3. Это существенно для моей задачи.

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

То есть коллизии со структуированными значениями, парами к примеру, намного чаще встречаются?

Понятия не имею, как реализован хеш для структурированных элементов (и реализован ли вообще). Но хеши для строк тестируют куча людей в своём коде и если бы коллизии были частыми, то воя было бы много.

Norgat ★★★★★ ()
Ответ на: комментарий от pseudo-cat

еще раз: хеш-таблица не умеет сама принимать в качестве ключей оные пары (оно там вроде как не «два значения через запятую», а отдельный тип tuple)? Где видел, стандартные ассоциативные массивы могут иметь ключами любой тип, для которого реализованы хеш (для хеш-таблиц) и равенство, и сами разгребают коллизии. Зачем сразу изобретать велосипеды?

arkhnchul ★★ ()
Последнее исправление: arkhnchul (всего исправлений: 1)
Ответ на: комментарий от Norgat

Коллизии крайне редки. Тебе придётся постараться, чтобы напороться.

тем не менее, это вполне возможный источник трудноуловимых багов. Делать так, зная о возможности напороться - довольно злобное буратинство.

arkhnchul ★★ ()
Ответ на: комментарий от pseudo-cat

Хэш-множества дают точно такой же быстрый доступ, как и хэш-таблицы. По сути, это одна и та же структура данных.

Zenom ★★★ ()
Ответ на: комментарий от arkhnchul

Не очень понял, зачем ещё раз повторять, я и так это отлично понимаю)

pseudo-cat ★★★ ()
Ответ на: комментарий от Zenom

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

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

я и так это отлично понимаю)

к примеру как?

цота непохозе)

как и вкуда добавляется элемент сейчас? Пример кода с указанием типов.

arkhnchul ★★ ()
Ответ на: комментарий от pseudo-cat

Не надо вычислять хэш-код элемента. Множество это делает самостоятельно и самостоятельно же решает коллизии. Надо просто складывать пары индексов в множество.

Zenom ★★★ ()
Ответ на: комментарий от Zenom

вы имеете в виду, что при добавлении в HashSet новый элемент сравнивается с каждым уже имеющемся элементом с помощью Equals, а в случае с HashTable сравнивается только GetHashCode? Если так, то видимо это и есть причина тормознутости HashSet в случаях, когда создаётся много таких объектов.

pseudo-cat ★★★ ()
Ответ на: комментарий от arkhnchul
let ht = HashTable()
let getData keys =
   match ht.Contains(hash keys) with
   | true -> ht.Item(hash keys)
   | false -> 
       let data = 
           keys |> List.collect (fun k -> dataProvider.Get(k))
       ht.Add(hash keys, data)
       data

код схематичный

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

Нет, не с каждым. HashSet и HashTable работают одинаково. Сравниваются только те ключи, у которых совпал хэш-код.

Zenom ★★★ ()
Ответ на: комментарий от Zenom

ок, а в каких случаях тогда предпочтительна HastTable? И не очень понятно как происходит тогда обращение к элементу? То есть мы добавили элемент A с хэш-кодом 1, потом мы добавили элемент B с таким же хэш-кодом, но функция Equals(A, B) ложна. И под каким тогда ключом лежит B?

pseudo-cat ★★★ ()
Ответ на: комментарий от arkhnchul

так а что меняется? ну будет сама таблица вызвать GetHashCode, а результат тот же

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

так а что меняется? ну будет сама таблица вызвать GetHashCode, а результат тот же

сейчас HashMap считает хеш от хеша, а будет от объекта :)

anonymous ()

Надеяться на уникальность GetHashcode нельзя. Хочешь уникальных хешей, перепиши на sha256

Dark_SavanT ★★★★★ ()
Ответ на: комментарий от pseudo-cat

Легко. Я в своё время так накололся на GetHashCode от строк. Две разные строки боладали одним хешем.

Dark_SavanT ★★★★★ ()
Ответ на: комментарий от pseudo-cat

Все знакомые мне стандартные языковые реализации хеш-таблиц корректно обрабатывают коллизии - при совпадении хешей ключей идет проверка на равенство самих ключей.

Т.е. вот сейчас что происходит:

1) берется объект, логически являющийся ключом, вычисляется его хеш

2) значение этого хеша фактически используется в качестве ключа, по нему в таблицу помещается некое значение. При помещении значения таблица вычисляет хеш от ключа (который сам по себе уже хеш), проверяет, что такого хеша у нее не имеется, размещает новое значение.

....

n) берется объект, блабла, вычисляется хеш, и вдруг так получается, что он совпадает с ранее вычисленным для другого объекта ключа - коллизия. Об этом никто не знает и не отлавливает.

n+1) значение этого хеша используется в качестве ключа. В таблицу помещается значение. Таблица видит, что хеш такого ключа (который сам по себе хеш) в ней уже есть, проверяет равенство самого нового ключа и имеющегося, они равны - коллизия произошла на предыдущем этапе вне таблицы - и затирает старое значение новым.

Видим, где косяк? Теперь используем в качестве ключа сам объект:

1) объект фактически используется в качестве ключа, по нему в таблицу помещается некое значение. При помещении значения таблица вычисляет хеш от ключа (который теперь объект), проверяет, что такого хеша у нее не имеется, размещает новое значение.

....

n) берется объект, логически выступающий в качестве ключа

n+1) объект используется в качестве ключа. В таблицу помещается значение. Таблица видит, что хеш такого ключа (который теперь объект) в ней уже есть, проверяет равенство самого нового ключа и имеющегося, они не равны - коллизия. Таблица обрабатывает ее своими механизмами - зачастую это означает, что хэш теперь указывает на некий массив, а не на одну пару «ключ-значение».

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

arkhnchul ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.