Java中用于浮点数的哈希码 [英] Hash Codes for Floats in Java

查看:123
本文介绍了Java中用于浮点数的哈希码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有两个浮点变量和 hashCode 方法的类(当前代码段中不等于):

I have a class with two float variables and hashCode method (without equals in current code snippet):

public class TestPoint2D {
    private float x;
    private float z;

    public TestPoint2D(float x, float z) {
        this.x = x;
        this.z = z;
    }

    @Override
    public int hashCode() {
        int result = (x != +0.0f ? Float.floatToIntBits(x) : 0);
        result = 31 * result + (z != +0.0f ? Float.floatToIntBits(z) : 0);
        return result;
    }
}

以下测试

@Test
public void tempTest() {
    TestPoint2D p1 = new TestPoint2D(3, -1);
    TestPoint2D p2 = new TestPoint2D(-3, 1);

    System.out.println(p1.hashCode());
    System.out.println(p2.hashCode());
}

返回相同的值:

-2025848832

-2025848832

在这种情况下,我不能在HashSet/HashMap中使用TestPoint2D

In this case I can't use my TestPoint2D within HashSet / HashMap

在这种情况下,任何人都可以建议如何实现 hashCode 或与此相关的变通办法吗?

Can anyone suggest how to implement hashCode in this case or workarounds related to this?

P.S. 添加了另一项测试:

P.S. Added one more test:

@Test
public void hashCodeTest() {
    for (float a = 5; a < 100000; a += 1.5f) {
        float b = a + 1000 / a; // negative value depends on a
        TestPoint3D p1 = new TestPoint3D(a, -b);
        TestPoint3D p2 = new TestPoint3D(-a, b);
        Assert.assertEquals(p1.hashCode(), p2.hashCode());
    }
}

它通过证明了

TestPoint2D(a, -b).hashCode() == TestPoint2D(-a, b).hashCode()

推荐答案

这些自动生成的哈希码功能不是很好.

These auto-generated hashcode functions are not very good.

问题在于小整数会导致非常稀疏"且相似的位码.

The problem is that small integers cause very "sparse" and similar bitcodes.

要了解该问题,请查看实际计算.

To understand the problem, look at the actual computation.

System.out.format("%x\n", Float.floatToIntBits(1));
System.out.format("%x\n", Float.floatToIntBits(-1));
System.out.format("%x\n", Float.floatToIntBits(3));
System.out.format("%x\n", Float.floatToIntBits(-3));

给予:

3f800000
bf800000
40400000
c0400000

如您所见,-是IEEE浮点数中的最高有效位.与31相乘不会对其产生实质性影响:

As you can see, the - is the most significant bit in IEEE floats. Multiplication with 31 changes them not substantially:

b0800000
30800000
c7c00000
47c00000

问题在于结尾处全为0.通过与任何素数的整数乘法来保留它们(因为它们是以2为基数0,而不是以10为基数!).

The problem are all the 0s at the end. They get preserved by integer multiplication with any prime (because they are base-2 0s, not base-10!).

所以恕我直言,最好的策略是采用移位,例如:

So IMHO, the best strategy is to employ bit shifts, e.g.:

final int h1 = Float.floatToIntBits(x);
final int h2 = Float.floatToIntBits(z);
return h1 ^ ((h2 >>> 16) | (h2 << 16));

但是您可能希望查看哪个哈希该算法最适合唯一性和速度? test 针对您的整数浮点数的特殊情况.

But you may want to look at Which hashing algorithm is best for uniqueness and speed? and test for your particular case of integers-as-float.

这篇关于Java中用于浮点数的哈希码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆