Hashcode实现双精度

时间:2011-04-18 13:26:53

标签: c# floating-point precision hashcode

我以前曾问过这个课程的问题,但这里又是一个问题。

我创建了一个Complex类:

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

我正在实现EqualsHashcode函数,而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;
    }

这很有效,当Imaginary和Real部分彼此非常接近时,它说它们是相同的。

现在我正在尝试实现HashCode函数,我使用了一些John skeet在这里使用的示例,目前我有以下内容。

    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 个答案:

答案 0 :(得分:5)

首先,您的Equals()实施已被破坏。阅读here以了解原因。

其次,这种“模糊等于”打破了Equals()的契约(一件事情不具有传递性),因此使用Hashtable将无效,无论你如何实施GetHashCode()

对于这种事情,你真的需要一个空间索引,例如R-Tree

答案 1 :(得分:1)

计算哈希值时只需删除精度。

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是精确值

答案 2 :(得分:1)

我看到两个简单的选择:

  • 使用十进制而不是双
  • 不使用Real.GetHashCode,而是使用Real.RoundTo6Ciphers()。GetHashCode()。

然后你将拥有相同的哈希码。

答案 3 :(得分:0)

我会创建将Real和Imaginary舍入到最接近的千分之一的只读属性,然后在这些getter属性上执行equals和hashcode实现。