[英]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.