如果您有Vec<u32>
,则可以使用slice::binary_search
方法。
由于我不明白的原因,f32
和f64
未实施Ord
。由于原始类型来自标准库,因此您无法自己对它们实现Ord
,因此您似乎无法使用此方法。
你怎么能有效地做到这一点?
我是否真的必须将f64
包装在包装器结构中并在其上实现Ord
?这样做似乎非常痛苦,并且需要大量的transmute
来无条件地来回摆放数据块,实际上没有理由。
答案 0 :(得分:27)
由于我不明白的原因,f32和f64没有实现Ord。
因为floating point is hard!简短版本是浮点数具有特殊值NaN - 非数字。浮点数的IEEE规范指出1 < NaN
,1 > NaN
和NaN == NaN
都是false
。
Ord
说:
构成total order。
的类型的特征
这意味着比较需要 totality :
a≤b或b≤a
但我们刚看到浮点没有这个属性。
所以是的,您需要创建一个包装类型,以某种方式处理large number of NaN values的比较。也许你的情况你可以断言浮点值永远不是NaN然后调出常规的PartialOrd
特征。这是一个例子:
use std::cmp::Ordering;
#[derive(PartialEq,PartialOrd)]
struct NonNan(f64);
impl NonNan {
fn new(val: f64) -> Option<NonNan> {
if val.is_nan() {
None
} else {
Some(NonNan(val))
}
}
}
impl Eq for NonNan {}
impl Ord for NonNan {
fn cmp(&self, other: &NonNan) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
fn main() {
let mut v: Vec<_> = [2.0, 1.0, 3.0].iter().map(|v| NonNan::new(*v).unwrap()).collect();
v.sort();
let r = v.binary_search(&NonNan::new(2.0).unwrap());
println!("{:?}", r);
}
答案 1 :(得分:6)
切片方法之一是binary_search_by
,您可以使用它。 f32
/ f64
实施PartialOrd
,如果您知道他们永远成为NaN
,您可以打开partial_cmp
的结果:
fn main() {
let values = [1.0, 2.0, 3.0, 4.0, 5.0];
let location = values.binary_search_by(|v| {
v.partial_cmp(&3.14).expect("Couldn't compare values")
});
match location {
Ok(i) => println!("Found at {}", i),
Err(i) => println!("Not found, could be inserted at {}", i),
}
}
答案 2 :(得分:1)
https://github.com/emerentius/ord_subset实现了一个ord_subset_binary_search()
方法,您可以将其用于此目的。
来自他们的自述文件:
let mut s = [5.0, std::f64::NAN, 3.0, 2.0];
s.ord_subset_sort();
assert_eq!(&s[0..3], &[2.0, 3.0, 5.0]);
assert_eq!(s.ord_subset_binary_search(&5.0), Ok(2));
assert_eq!(s.iter().ord_subset_max(), Some(&5.0));
assert_eq!(s.iter().ord_subset_min(), Some(&2.0));
答案 3 :(得分:1)