Java 如何更正哈希函数?
此问题是提交给at的答复的结果Java 如何更正哈希函数?,java,hash,numbers,double,Java,Hash,Numbers,Double,此问题是提交给at的答复的结果 我有一个名为Point的类,它基本上是“用来封装二维空间中表示的点”。我重写了hashcode()函数,如下所示: ... @Override public int hashCode() { int hash = 0; hash += (int) (Double.doubleToLongBits(this.getX()) ^ (Double.doubleToLongBits(this.getX()) >>>
我有一个名为
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;
}
...
让我澄清一下(对于那些没有检查上述链接的人),我的点使用两个double
s:x
和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());
}
我得到输出:
这显然是一个问题。基本上,我希望我的hashcode()
为相等的点返回相等的hashcode。如果我颠倒其中一个参数声明的顺序(即,在其中一个参数声明中将12
与1
交换以获得相等的点
s),我将得到正确(相同)的结果。如何在保持散列的质量或唯一性的同时纠正我的方法?这可能是一个愚蠢的想法,因为您使用的是+这是一种对称运算,您会遇到对称问题。如果使用非对称运算,如除法(检查分母==0)或减法,该怎么办?或者你可以在文献中找到或自己发明的任何其他数字。如果没有关于双精度中数字性质的更多信息,你无法获得两个唯一双精度的整数哈希代码
为什么?
int存储为32位表示,双精度存储为64位表示()
因此,您试图在32位空间中存储128位信息,因此它永远不会给出唯一的散列
但是
这真的不是,散列码
只需要有相当罕见的碰撞就可以了
如果你
了解一些关于双倍数字的知识,这会减少它们的影响
熵/信息量然后你可以用它来压缩
它们使用的位数。这将取决于申请
你还没有讨论过的这门课李>
这就是为什么平等
通常不使用哈希代码检查是否相等,
使用每个点的getX和getY进行比较
您不能使用中已经存在的代码吗
例如,这就是番石榴在中国的用途
如果您有Java 7,只需:
Objects.hash(x,y)
试试这个
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(双a[])
模式。
它生成以下哈希代码:
-992476223
1076364225
您可以找到如何在有效的Java项目中编写好的哈希代码的建议。9在IDE中单击鼠标右键,选择“生成equals和hashCode”,然后检查IDE生成的正确实现。或者使用Objects.hash(x,y)
。通常-要生成有意义的hashCode()
,每次在计算中引入另一个属性时都必须将其移动。这将导致完全相同的对称问题。他最好使用数组.hashCode(新的double[]{x,y})
,或者干脆使用对象.hash(x,y)
。请注意。。。我之所以接受这个答案,是因为它是最短(也是最简单)的答案。请更详细地解释为什么使用31
?就因为31是质数?我可以改用23
吗?嗯。。。有趣。似乎NetBeans
也使用了这种策略:inthash=5;hash=41*hash+(int)(Double.doubleToLongBits(this.x)^(Double.doubleToLongBits(this.x)>>>32));hash=41*hash+(int)(Double.doubleToLongBits(this.y)^(Double.doubleToLongBits(this.y)>>>32));返回散列代码>@ADS:请参阅有效的Java项目。9:选择值31是因为它是奇数素数…请注意,虽然这唯一地区分了这两点,但并非所有点都能保证。(见上面我的帖子)。这确实取决于计算散列的目标。
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;
}
-992476223
1076364225