您可以将f64
拆分为整数部分和小数部分,并以以下方式将它们存储在结构体中:
#[derive(Hash, Eq, PartialEq)]
struct Distance {
integral: u64,
fractional: u64
}
其余部分很简单:
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)));
}
编辑:如Veedrac所说,一种更通用和高效的选项是将f64
分解为尾数-指数-符号三元组。可以执行此操作的函数为integer_decode()
,但在std
中该函数已被弃用,不过可以在Rust GitHub中轻松找到。
integer_decode()
函数的定义如下:
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)
}
Distance的定义可以是:
#[derive(Hash, Eq, PartialEq)]
struct Distance((u64, i16, i8));
impl Distance {
fn new(val: f64) -> Distance {
Distance(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));
assert_eq!(map.get(&Distance::new(0.4)), Some(&f64::hypot(4.2, 50.0)));
}
f64
没有实现Eq
的问题,但我认为问题更深层次 => 即使你排除了NaN
,比较两个浮点数的相等性也会引起麻烦。 - Matthieu M.