Реализация хэш-кода двойной точности - PullRequest
5 голосов
/ 18 апреля 2011

Я задавал вопрос об этом классе раньше, но вот еще раз.

Я создал сложный класс:

 public class Complex
 {
        public double Real { get; set; }
        public double Imaginary { get; set; }
 }

И я реализую функции Equals и Hashcode, а функция Equal учитывает определенную точность. Для этого я использую следующую логику:

    public override bool Equals(object obj)
    {
        //Some default null checkint etc here, the next code is all that matters.
        return Math.Abs(complex.Imaginary - Imaginary) <= 0.00001 &&
            Math.Abs(complex.Real - Real)  <= 0.00001;
    }

Ну, это работает, когда Воображаемая и Реальная части действительно близки друг к другу, они говорят, что они одинаковы.

Теперь я пытался реализовать функцию HashCode, я использовал несколько примеров, которые использовал Джон Скит, в настоящее время у меня есть следующее.

    public override int GetHashCode()
    {
        var hash = 17;
        hash = hash*23 + Real.GetHashCode();
        hash = hash*23 + Imaginary.GetHashCode();
        return hash;
    }

Однако это не учитывает ту точность, которую я хочу использовать. Итак, в основном следующие два класса:

Complex1[Real = 1.123456; Imaginary = 1.123456]

Complex2[Real = 1.123457; Imaginary = 1.123457]

Являются ли Equal, но не предоставляют тот же HashCode, как мне этого добиться?

Ответы [ 4 ]

6 голосов
/ 18 апреля 2011

Прежде всего, ваша Equals() реализация не работает. Прочитайте здесь , чтобы понять, почему.

Во-вторых, такое «нечеткое равенство» нарушает контракт Equals() (это не транзитивно, во-первых), поэтому использование его с Hashtable не будет работать , независимо от того, как вы реализуете GetHashCode().

Для такого рода вещей вам действительно нужен пространственный индекс, такой как R-Tree .

2 голосов
/ 18 апреля 2011

Просто уменьшите точность при вычислении хеш-значения.

public override int GetHashCode()
{
    var hash = 17;
    hash = hash*23 + Math.Round(Real, 5).GetHashCode();
    hash = hash*23 + Math.Round(Imaginary, 5).GetHashCode();
    return hash;
}

, где 5 - ваше значение точности

1 голос
/ 18 апреля 2011

Я вижу два простых варианта:

  • Использовать десятичное число вместо двойного
  • Вместо использования Real.GetHashCode используйте Real.RoundTo6Ciphers (). GetHashCode ().

Тогда у вас будет тот же хеш-код.

0 голосов
/ 18 апреля 2011

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

...