用于浮点数的java哈希码

时间:2014-03-25 09:57:33

标签: java floating-point hashcode

我想将Double(或Float)用作Hashmap

中的键
Map<Double, String> map = new HashMap<Double, String>()
map.put(1.0, "one");
System.out.println(map.containsKey(Math.tan(Math.PI / 4)));

然后返回false。

如果我比较这两个数字,我会做这样的事情

final double EPSILON = 1e-6;
Math.abs(1.0 - Math.tan(Math.PI / 4)) < EPSILON

但是,由于Hashmap会使用hashcode,因此对我来说会破坏事情。

我想实现一个roundKey函数,在将EPSILON用作关键字之前将其舍入到map.put(roundKey(1.0), "one") map.containsKey(roundKey(Math.tan(Math.PI / 4))) 的某个倍数

roundKey
  • 有更好的方法吗?
  • 实施此{{1}}
  • 的正确方法是什么

2 个答案:

答案 0 :(得分:4)

如果你知道哪种舍入是合适的,你可以使用它。例如如果你需要舍入到美分,你可以舍入到小数点后两位。

但是,对于上面的示例,离散舍入到固定精度可能不合适。例如如果你舍入到6个小数位,1.4999e-6和1.5001e-6将不匹配,因为一个向上舍入而另一个向下,即使差值是&lt;&lt; 1E-6。

在这种情况下,您可以做的最接近的是使用NavigableMap

NavigableMap<Double, String> map = new TreeMap<>();

double x = ....;
double error = 1e-6;

NavigableMap<Double, String> map2 = map.subMap(x - error, x + error);

或者您可以使用

Map.Entry<Double, String> higher = map.higherEntry(x);
Map.Entry<Double, String> lower = map.lowerEntry(x);
Map.Entry<Double, String> entry = null;
if (higher == null)
    entry = lower;
else if (lower == null)
    entry = higher;
else if (Math.abs(lower.getKey() - x) < Math.abs(higher.getkey() - x))
    entry = lower;
else
    entry = higher;
// entry is the closest match.
if (entry != null && Math.abs(entry - x) < error) {
    // found the closest entry within the error
}

这将找到连续范围内的所有条目。

答案 1 :(得分:-1)

最好的方法是不要使用浮点数作为键,因为它们(如你所发现的那样)不会比较 Kludgy“解决方案”就像把它们称为相同但如果它们在彼此的某个范围内只会导致后来出现问题,因为你要么必须延长过滤器或使其更加严格,都会导致潜在的问题使用现有代码,和/或人们会忘记事情应该如何运作。
当然,在某些应用程序中,您希望这样做,但作为查找内容的关键?不。你可能最好使用度数角度,以及整数,这里的关键。如果您需要比1度更高的精度,请使用例如1度的角度。通过存储0到3600的数字十分之一 这将为您提供可靠的地图行为,同时保留您计划存储的数据。