C# 二维点结构的“GetHashCode()”算法(避免冲突)是什么

C# 二维点结构的“GetHashCode()”算法(避免冲突)是什么,c#,hashcode,point,C#,Hashcode,Point,考虑以下代码: struct Vec2 : IEquatable<Vec2> { double X,Y; public bool Equals(Vec2 other) { return X.Equals(other.X) && Y.Equals(other.Y); } public override bool Equals(object obj) { if (obj is Vec2)

考虑以下代码:

struct Vec2 : IEquatable<Vec2>
{
    double X,Y;

    public bool Equals(Vec2 other)
    {
        return X.Equals(other.X) && Y.Equals(other.Y);
    }

    public override bool Equals(object obj)
    {
        if (obj is Vec2)
        {
            return Equals((Vec2)obj);
        }
        return false;
    }

    // this will return the same value when X, Y are swapped
    public override int GetHashCode()
    {
        return X.GetHashCode() ^ Y.GetHashCode();
    }

}
这将破坏一本字典的收藏。因此,问题是如何为2、3甚至4个浮点值形成
GetHashCode()
函数的属性,以使结果不对称且哈希不冲突

编辑1:
Point
实现不适当的
x^y
解决方案,并
PointF
包装
ValueType.GetHashCode()

Rectangle
有一个非常特殊的
((X^((Y>19)))^((宽度>6))^((高度>25))
哈希代码表达式,它的性能似乎与预期的一样

编辑2:

“St.Bug”有一个很好的实现,因为它不考虑每个比特同样重要的

public override unsafe int GetHashCode() //from System.Double
{
    double num = this;
    if (num == 0.0)
    {
        return 0;
    }
    long num2 = *((long*) &num);
    return (((int) num2) ^ ((int) (num2 >> 32)));
}

Jon skeet对此进行了介绍:

另外,将
Equals(object)
实现更改为:

return Equals(obj as FVector2);
但是请注意,这可能会认为派生类型是相等的。如果您不想这样做,您必须将运行时类型
other.GetType()
typeof(FVector2)
进行比较(不要忘记空性检查)感谢您指出它是一个结构,LukH

Resharper具有很好的代码生成功能,可以生成相等代码和哈希代码,因此,如果您有Resharper,您可以让它完成它的工作

哈希冲突不会对字典集合造成严重破坏。如果你运气不好得到它们,它们会降低效率,但是字典必须处理它们

如果可能的话,冲突应该很少发生,但这并不意味着实现是错误的。XOR通常是不好的,因为您已经给出了(高碰撞)的原因——ohadsc已经发布了我之前给出的一个示例,作为替代,这应该是好的

请注意,要实现无冲突的
Vec2
,是不可能的-从
GetHashCode
中只有232个可能的返回值,但有更多可能的X和Y值,即使在删除NaN和无限值之后


Eric Lippert有一个on
GetHashCode
,您可能会发现它很有用。

如果哈希代码的大小小于结构的大小,那么冲突是不可避免的。

坐标的合理界限是什么

除非它可以是所有可能的整数值,否则您可以简单地:

const SOME\u LARGE\u NUMBER=100000;
返回一些大的数字*x+y

哈希码方法适用于整数坐标,但不建议用于浮点值。使用浮点坐标,可以使用排序序列结构创建点集/点池

排序序列是一个叶版本的平衡二叉树


这里的关键点是点坐标

以最小化冲突为目标是可以的,但您的代码必须预料到它们;它们总是会发生冲突-
int
的可能值范围小于
double
,与
double
相比,它甚至更小。此外,您可能需要考虑一个更宽松的相等性比较——由于舍入,两个浮点值可能非常接近(任何人通过眼睛进行比较)会考虑相等,但仍然不完全相等。由于X^X-->0 all(C,C)与all(D,D)发生冲突,这是一个更大的冲突空间。所讨论类型的可能副本是一个结构,因此不能将
Equals(object)
实现更改为使用
as
。OP当前的
Equals(object)
方法没有问题。这可能很有效,但如果您查看
Double.GetHashCode()
的计算,您会注意到使用了更仔细的重要位,我也愿意这样做。感谢您的回复,因为我已经为许多结构实现了这个版本。很高兴能提供帮助!请注意,当字段是浮点数时,位不是稠密的,而是遵循特定的模式,为结构提供合理的数字。因此,如果异或运算避免了最高有效位的对称性,那么它就足够了。这有意义吗?@ja72:可能。这取决于真实世界的数据。如果它们实际上是整数,这仍然很糟糕,但与(X=1,Y=5)和(X=5,Y=1)的冲突是不可接受的。与(3.287e308,-7,.228e175)及其对称对的冲突更容易接受。如果您知道边界,这确实是最好的。您也可以使用
int
s和
int.MaxValue
unchecked
clause来表示
int
s。您可以显示一些代码来解释您提到的内容。我很难想象它。我知道浮点精度会使
GetHashCode()
变得不确定,但我不明白你打算如何解决这个问题。忘记GetHashCode(),你不使用哈希。刚刚使用了一个带xy比较器的平衡二叉树。我经常需要实现
IEquatable
,因此需要使用哈希来覆盖。你能展示一些代码让我们理解你在说什么吗?顺便说一句,你可以使用快照网格转换成整数,然后使用这些函数中的一个进行哈希运算而不产生冲突。以唯一和确定的方式将两个整数映射为一个整数。
   public override int GetHashCode()
   {
       unchecked // Overflow is fine, just wrap
       {
           int hash = 17;
           // Suitable nullity checks etc, of course :)
           hash = hash * 23 + X.GetHashCode();
           hash = hash * 23 + Y.GetHashCode();
           return hash;
       }
   }
return Equals(obj as FVector2);