如果您知道您的数据不包含 NaN,则通过展开比较来断言该事实:
fn example(x: &[f64]) -> Option<f64> {
x.iter()
.cloned()
.min_by(|a, b| a.partial_cmp(b).expect("Tried to compare a NaN"))
}
如果您的数据可能有 NaN,您需要专门处理这种情况。一种解决方案是说all 16,777,214 NaN values 彼此相等并且总是大于或小于其他数字:
use std::cmp::Ordering;
fn example(x: &[f64]) -> Option<f64> {
x.iter()
.cloned()
.min_by(|a, b| {
// all NaNs are greater than regular numbers
match (a.is_nan(), b.is_nan()) {
(true, true) => Ordering::Equal,
(true, false) => Ordering::Greater,
(false, true) => Ordering::Less,
_ => a.partial_cmp(b).unwrap(),
}
})
}
有许多可用的 crate 可用于为您提供代码所需的任何语义。
您应该不使用partial_cmp(b).unwrap_or(Ordering::Equal),因为当存在 NaN 时它会提供不稳定的结果,但它会让读者认为它们已被处理:
use std::cmp::Ordering;
use std::f64;
fn example(x: &[f64]) -> Option<f64> {
x.iter()
.cloned()
.min_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal))
}
fn main() {
println!("{:?}", example(&[f64::NAN, 1.0]));
println!("{:?}", example(&[1.0, f64::NAN]));
}
Some(NaN)
Some(1.0)