[英]java hashcode for floating point numbers
我想使用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
因此对我来说很Hashmap
。
我想实现一个roundKey
函数,在将它用作键之前将其四舍五入到EPSILON
倍数
map.put(roundKey(1.0), "one")
map.containsKey(roundKey(Math.tan(Math.PI / 4)))
roundKey
的正确方法 如果您知道合适的舍入方法,则可以使用它。 例如,如果需要四舍五入到美分,则可以四舍五入到小数点后两位。
但是,对于上面的示例,将离散舍入到固定精度可能不合适。 例如,如果四舍五入到小数点后六位,则即使相差<< << 1e-6,1.4999e-6和1.5001e-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
}
这将找到连续范围内的所有条目。
最好的方法是不要使用浮点数作为键,因为它们(如您所发现的)不会进行比较。
Kludgy的“解决方案”就像在它们彼此处于一定范围之内时称它们相同,只会在以后导致问题,因为您要么不得不拉伸过滤器,要么使过滤器的时间变得更加严格,两者都会导致潜在的问题与现有的代码,和/或人们会忘记事情应该如何工作。
当然,在某些应用程序中您想这样做,但是作为查找内容的关键吗? 不。您最好使用角度(以度为单位)和整数(如此处的键)。 如果需要大于1度的精度,请通过存储0到3600之间的数字来使用角度(例如十分之一度)。
这将为您提供可靠的Map行为,同时保留您计划存储的数据。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.