如何更正哈希函数?

时间:2014-04-04 10:47:15

标签: java hash numbers double

此问题是my postCodeReview提交给{{3}}的回复的结果。


我有一个名为class的{​​{1}},它基本上是“用于封装在2D空间中表示的”。我已经覆盖了Point函数,如下所示:

hashcode()

让我澄清(对于那些没有查看上述链接的人)我的... @Override public int hashCode() { int hash = 0; hash += (int) (Double.doubleToLongBits(this.getX()) ^ (Double.doubleToLongBits(this.getX()) >>> 32)); hash += (int) (Double.doubleToLongBits(this.getY()) ^ (Double.doubleToLongBits(this.getY()) >>> 32)); return hash; } ... 使用两个Pointdoublex来表示其坐标

问题:
当我运行这个方法时,我的问题很明显:

y

我得到输出:

public static void main(String[] args) {
    Point p1 = Point.getCartesianPoint(12, 0);
    Point p2 = Point.getCartesianPoint(0, 12);
    System.out.println(p1.hashCode());
    System.out.println(p2.hashCode());
}

这显然是个问题。基本上我打算让我的1076363264 1076363264 返回相等的哈希码以获得相等的点。如果我在其中一个参数声明中反转顺序(即在其中一个中交换hashcode()并使用12得到相等的1 s),我得到正确的(相同的)结果。如何在保持哈希的质量唯一性的同时纠正我的方法?

4 个答案:

答案 0 :(得分:5)

如果没有关于双打中数字性质的数据的更多信息,则无法获得两个唯一的双精度的整数哈希码。

<强>为什么吗

int存储为32位表示,双精度存储为64位表示(see the Java tutorial)。

因此,您试图在32位空间中存储128位信息,因此它永远不会给出唯一的哈希值。

<强>然而

  1. 这真的不是the purpose of a hash code哈希码 只需要有相当罕见的碰撞才有用。
  2. 如果你 知道关于双数的东西,这减少了它们 熵/信息内容然后你可以使用它来压缩 他们使用的位数。这取决于应用程序 你还没有讨论过这个课程。
  3. 这就是为什么等于 通常不会使用哈希码来检查相等性, 使用每个Point的getX和getY来进行比较。

答案 1 :(得分:3)

试试这个

public int hashCode() {
    long bits = Double.doubleToLongBits(x);
    int hash = 31 + (int) (bits ^ (bits >>> 32));
    bits = Double.doubleToLongBits(y);
    hash = 31 * hash + (int) (bits ^ (bits >>> 32));
    return hash;
}

此实现遵循Arrays.hashCode(double a[])模式。 它产生这些哈希码:

-992476223
1076364225

您可以找到有关如何在Effective Java Item中编写好hashCode的建议。 9

答案 2 :(得分:1)

这可能是一个愚蠢的想法,如果你正在使用+这是一个对称操作,你就会遇到对称问题。如果您使用非对称操作(例如除法(检查分母== 0)或减去?或者你在文学中找到或发明自己的任何其他东西。

答案 3 :(得分:1)

您是否已使用Arrays.hashCode中已存在的代码?

  Arrays.hashCode(new double[]{x,y});

这就是番石榴在Objects.hashCode.

中使用的例子

如果你有Java 7,只需:

 Objects.hash(x,y)