本文介绍了我如何使用f64的HashMap作为Rust中的键?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我想用 HashMap< f64,f64> 来保存已知x和关键点y到另一个点的距离。 f64 作为值不应该在这里,焦点应该在关键。 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的类型需要浮点精度,但是如果对 f64 不起作用,我将使用 i64 使用已知的指数。 我使用自己的 struct Dimension(f64)尝试了一些黑客行为,然后通过将float转换为一个 String 来实现 Hash ,然后对其进行散列。 #[derive(PartialEq,Eq)] struct DimensionKey(f64); $ b $ impl Hash for DimensionKey { fn hash< H:Hasher>(&self; state:&mut H){ format!({},self 0.0).hash(状态); $ b看起来非常糟糕,或浮动为基数和指数的整数似乎是相当复杂的只是一个关键。 更新:我可以保证我的关键永远不会是 NaN ,或者一个无限的值。另外,我不会计算我的密钥,只是迭代它们并使用它们。所以在 0.1 + 0.2≠0.3 的已知错误中应该没有错误。 如何进行二进制搜索在一个浮点数的Vec?,这个问题有一个共同的实现一个浮点数的总排序和相等性,区别只在于散列或迭代。 f64 拆分为整数和小数部分,并按照以下方式将它们存储在结构中: > #[派生(Hash,Eq,PartialEq)] 结构距离{积分:u64,分数:u64 } 其余部分很简单: 使用std :: collections :: HashMap; $ b#[derive(Hash,Eq,PartialEq)] struct距离{积分:u64,分数:u64 } impl距离{ fn new(i:u64,f:u64) - >距离{距离{积分:我,分数:f } } } fn main { let mut map:HashMap< Distance,f64> = HashMap :: new(); map.insert(Distance :: new(0,4),f64 :: hypot(4.2,50.0)); map.insert(Distance :: new(1,8),f64 :: hypot(2.6,50.0)); (& LT;距离::新(0,4)),一些(& f64 :: hypot(4.2,50.0))); assert_eq!(map.get code 编辑:正如Veedrac所说,高效的选择是将 f64 解构为尾数 - 指数 - 符号三元组。可以这样做的函数, integer_decode( ) 在 std 中不推荐使用,但可以在 Rust GitHub 。 integer_decode()函数可以定义如下: $ p $ 使用std :: mem; fn integer_decode(val:f64) - > (u64,i16,i8){ let bits:u64 = unsafe {mem :: transmute(val)}; 让sign:i8 = if bits>> 63 == 0 {1} else {-1}; let mut指数:i16 =((bits> gt; 52)& 0x7ff)为i16; 让尾数= if指数== 0 {(bits& 0xfffffffffffff)<< 1 } else {(bits& 0xfffffffffffff)| 0x10000000000000 }; 指数 - = 1023 + 52; (尾数,指数,符号)} 定义距离然后可以是: #[derive(Hash,Eq,PartialEq) ] struct距离((u64,i16,i8)); impl距离{ fn new(val:f64) - >距离(距离(integer_decode(val))} } fn main(){ let mut map:HashMap< Distance ,f64> = HashMap :: new(); map.insert(Distance :: new(0.4),f64 :: hypot(4.2,50.0)); map.insert(Distance :: new(1.8),f64 :: hypot(2.6,50.0)); (& LT;距离::新(0.4)),一些(& f64 :: hypot(4.2,50.0))); assert_eq!(map.get } I want to use a HashMap<f64, f64>, for saving the distances of a point with known x and key y to another point. f64 as value shouldn't matter here, the focus should be on 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();As f64 is neither Eq nor Hash, but only PartialEq, f64 is not sufficient as a key. I need to save the distances first, but also access the distances later by y. The type of y needs to be floating point precision, but if doesn't work with f64, I'll use an i64 with an known exponent.I tried some hacks by using my own struct Dimension(f64) and then implementing Hash by converting the float into a String and then hashing it.#[derive(PartialEq, Eq)]struct DimensionKey(f64);impl Hash for DimensionKey { fn hash<H: Hasher>(&self, state: &mut H) { format!("{}", self.0).hash(state); }}It seems very bad and both solutions, my own struct or float as integers with base and exponent seem to be pretty complicated for just a key.Update:I can guarantee that my key never will be NaN, or an infinite value. Also, I won't calculate my keys, only iterating over them and using them. So there should no error with the known error with 0.1 + 0.2 ≠ 0.3.How to do a binary search on a Vec of floats? and this question have in common to implement total ordering and equality for a floating number, the difference lies only in the hashing or iterating. 解决方案 You could split the f64 into the integral and fractional part and store them in a struct in the following manner:#[derive(Hash, Eq, PartialEq)]struct Distance { integral: u64, fractional: u64}The rest is straightforward:use std::collections::HashMap;#[derive(Hash, Eq, PartialEq)]struct Distance { integral: u64, fractional: u64}impl Distance { fn new(i: u64, f: u64) -> Distance { Distance { integral: i, fractional: f } }}fn main() { let mut map: HashMap<Distance, f64> = HashMap::new(); map.insert(Distance::new(0, 4), f64::hypot(4.2, 50.0)); map.insert(Distance::new(1, 8), f64::hypot(2.6, 50.0)); assert_eq!(map.get(&Distance::new(0, 4)), Some(&f64::hypot(4.2, 50.0)));}Edit: As Veedrac said, a more general and efficient option would be to deconstruct the f64 into a mantissa-exponent-sign triplet. The function that can do this, integer_decode(), is deprecated in std, but it can be easily found in Rust GitHub.The integer_decode() function can be defined as follows:use std::mem;fn integer_decode(val: f64) -> (u64, i16, i8) { let bits: u64 = unsafe { mem::transmute(val) }; let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; let mantissa = if exponent == 0 { (bits & 0xfffffffffffff) << 1 } else { (bits & 0xfffffffffffff) | 0x10000000000000 }; exponent -= 1023 + 52; (mantissa, exponent, sign)}The definition of Distance could then be:#[derive(Hash, Eq, PartialEq)]struct Distance((u64, i16, i8));impl Distance { fn new(val: f64) -> Distance { Distance(integer_decode(val)) }}This variant is also easier to use:fn main() { let mut map: HashMap<Distance, f64> = HashMap::new(); map.insert(Distance::new(0.4), f64::hypot(4.2, 50.0)); map.insert(Distance::new(1.8), f64::hypot(2.6, 50.0)); assert_eq!(map.get(&Distance::new(0.4)), Some(&f64::hypot(4.2, 50.0)));} 这篇关于我如何使用f64的HashMap作为Rust中的键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
10-20 09:40