我想使用HashMap<f64, f64>
,用于保存一个已知x和key y的点到另一个点的距离。f64
作为值在这里不重要,重点应该是key。
let mut map = HashMap<f64, f64>::new();
map.insert(0.4, f64::hypot(4.2, 50.0));
map.insert(1.8, f64::hypot(2.6, 50.0));
...
let a = map.get(&0.4).unwrap();
字符串
由于f64
既不是Eq
也不是Hash
,而只是PartialEq
,所以f64
不足以作为密钥。我需要先保存距离,但稍后还要通过y访问距离。y的类型需要是浮点精度,但如果不适用于f64
,我将使用具有已知指数的i64
。
我尝试了一些技巧,使用我自己的struct Dimension(f64)
,然后通过将浮点数转换为String
并对其进行哈希来实现Hash
。
#[derive(PartialEq, Eq)]
struct DimensionKey(f64);
impl Hash for DimensionKey {
fn hash<H: Hasher>(&self, state: &mut H) {
format!("{}", self.0).hash(state);
}
}
型
这似乎非常糟糕,两种解决方案,我自己的结构或浮点数作为整数与基地和指数似乎是相当复杂的只是一个键。
更新:我可以保证我的key永远不会是NaN
,或者是一个无穷大的值。而且,我不会计算我的key,只会迭代它们并使用它们。所以0.1 + 0.2 ≠ 0.3
. How to do a binary search on a Vec of floats?的已知错误应该没有错误,这个问题与实现浮点数的全排序和相等是一样的,区别只在于哈希或迭代。
5条答案
按热度按时间am46iovg1#
您可以将
f64
拆分为整数和小数部分,并按以下方式将它们存储在结构中:字符串
剩下的很简单:
型
编辑:正如Veedrac所说,一个更通用、更有效的选择是将
f64
解构为一个尾数-指数-符号三元组。可以做到这一点的函数integer_decode()
在std
中已被弃用,但可以在Rust GitHub中轻松找到。integer_decode()
函数可以定义如下:型
Distance
的定义可以是:型
此变体也更易于用途:
型
pengsaosao2#
除了阅读所有其他评论和答案,以了解为什么你可能不想这样做之外,没有任何评论:
字符串
基本上,如果你想把
f64
当作一组没有意义的比特,那么,我们可以把它们当作一个大小相等的比特包,知道如何进行哈希和逐位比较。不要惊讶,当其中一个16 million
NaN
values doesn't equal another one。ltqd579y3#
不幸的是,浮点类型的相等性是hard and counter-intuitive:
字符串
因此哈希也很难,因为等值的哈希应该是相等的。
如果,在你的例子中,你有一个足够小的范围来适应你的数字在
i64
* 和 * 中,你可以接受精度的损失,那么一个简单的解决方案是首先规范化,然后根据规范值定义equal/hash:型
Hash
紧随其后,从那时起,您可以使用Distance
作为哈希Map中的键:型
**警告:**重申一下,此策略仅在以下情况下有效:(a)值的动态范围足够小,可以在
i64
(19位)中捕获,并且(b)动态范围事先已知,因为因子是静态的。幸运的是,这适用于许多常见问题,但它需要记录和测试。pengsaosao4#
您可以使用ordered_float crate来完成此操作。
uqzxnwby5#
对@Veedrac和@ljedraz已经说过的话做了很小的补充
有一个rust_decimal crate提供了
struct Decimal
,它是一个Copy
(所以只创建许多副本是有效的)。添加到
Cargo.toml
后:字符串
你的
DimensionKey
可能会变成这样:型