rust 如何得到包含浮点数的迭代器的最小值或最大值?

pinkon5k  于 2022-12-19  发布在  其他
关注(0)|答案(4)|浏览(225)

我理解why the floats don't have an implementation for Ord,但当我想偷懒使用迭代器时,这对我没有特别的帮助。
有没有一种变通方法或简单的方法可以获取包含浮点数的迭代器的最小值/ min / min_by?
我知道你可以排序(这很慢)或者用另一种类型 Package 它,然后实现所需的交易(这很冗长),但我希望能有更优雅的东西。

szqfcxe2

szqfcxe21#

浮点数有它们自己的minmax方法,可以一致地处理NaN,所以你可以折叠迭代器:

use std::f64;

fn main() {
    let x = [2.0, 1.0, -10.0, 5.0, f64::NAN];

    let min = x.iter().fold(f64::INFINITY, |a, &b| a.min(b));
    println!("{}", min);
}

打印-10
如果您想要不同的NaN处理方式,可以使用PartialOrd::partial_cmp。例如,如果您想要传播NaN,请使用以下命令折叠:

use std::f64;
use std::cmp::Ordering;

fn main() {
    let x = [2.0, 1.0, -10.0, 5.0, f64::NAN];

    let min = x.iter().fold(f64::INFINITY, |a, &b| {
        match PartialOrd::partial_cmp(&a, &b) {
            None => f64::NAN,
            Some(Ordering::Less) => a,
            Some(_) => b,
        }
    });
    println!("{}", min);
}
j2cgzkjk

j2cgzkjk2#

如果你知道你的数据不包含NaN,那么通过展开比较来Assert这个事实:

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(),
            }
        })
}

有许多可用的板条箱可用于给予代码所需的任何语义。
您不应该*****使用partial_cmp(b).unwrap_or(Ordering::Equal),因为当NaN存在时,它会提供不稳定的结果,但它会让读者认为它们已经得到处理:
一个二个一个一个

nfg76nw0

nfg76nw03#

自Rust 1.62.0起,一个名为.total_cmp()的内置浮点数总排序比较方法现在是稳定的。它实现了IEEE 754中定义的总排序,每个可能的f64位值都进行了不同的排序,包括正零和负零,以及所有可能的NaN。请注意,有些NaN排序在Infinity之上,有些NaN排序在-Infinity之下。因此,在NaN的存在下,“最大”值可能会混淆,但它将是一致的。
Floats仍然不会实现Ord,所以它们不能直接排序,但是样板文件已经被削减到一行,没有任何外部导入或恐慌的机会:

fn main() {
    let mut a: Vec<f64> = vec![2.0, 2.5, -0.5, 1.0, 1.5];
    
    let maximum = *a.iter().max_by(|a, b| a.total_cmp(b)).unwrap();
    println!("The maximum value was {maximum}.");

    a.sort_by(f64::total_cmp);
}
9fkzdhlc

9fkzdhlc4#

像这样?

fn main() {
    use std::cmp::Ordering;
    let mut x = [2.0, 1.0, -10.0, 5.0];
    x.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));
    println!("min in x: {:?}", x);
}

有一件事我很纠结,那就是sort_by会在适当的位置突变载体,因此您不能直接在链中使用它。

相关问题