Rust 中 f64 的最大值

13

我有一个价格向量 (f64),我想计算最高价格。

在Rust中,计算f64集合的最大值的当前最简单和最常用方式是什么?

关于Ordf64有些讨论,但我不确定最新和最不容易出错的方法是什么。

我依赖于以下内容,但我想象中应该有一些内置操作。

let max = prices.iter().fold(None, |r, &n| match r {
    Some(p) => Some(f64::max(p, n)),
    None => Some(e),
});

(这只是一些自由幺半群的折叠)

23
这不是回答您问题的答案,但请 使用浮点类型来表示价格。有许多陷阱,您永远无法摆脱。请使用整数来表示价格(例如以分为单位),或者使用完全精确的十进制类型(Decimal)。 - user2722968
确实不错的建议... - nicolas
5个回答

13

我不知道有其他的方法,但我以前用过以下方法:

let arr = [1.0, -42.0, 0.0, -5.0, 42.0, 7.0];
let max = arr.iter().copied().fold(f64::NAN, f64::max) // 42.0

1
FYI:copied() 是必需的,因为 f64::max 的签名是 f64::max(f64, f64)。如果没有 copied(),它将被调用为 f64::max(f64, &f64)(这是无效的)。 - ynn

13

另外一个选择是,自 Rust 1.59 开始,f32f64 都有一个total_cmp方法,您可以使用max_by方法与之配合。

arr.iter().max_by(|a, b| a.total_cmp(b))

Rust playground


(该代码为 Rust 语言的示例代码,在 Rust playground 上运行)

2
看起来 total_cmp 刚刚被批准了,所以它可能会在 1.59 版本中出现。 - David C. Bishop

9
从Rust 1.43开始,您可以这样编写代码:
my_iterator.fold(f64::NEG_INFINITY, f64::max)

解释:使用 f64::NEG_INFINITY 作为初始值,因为它是 f64::max 操作的中性元素。


3
当迭代器为空时,负无穷将影响您代码的其余部分。根据上下文,这可能是可以接受的,也可能会影响到下游处理。我之前写过这样的代码,但很重要的是确保对结果进行的计算不会被无限大卡住。Jason的答案存在同样的问题,但NaN倾向于比无限大更具有感染性,并以更明显的方式失败,因此如果预期迭代器永远不会为空,那么使用NaN可能更好。 - trent

6
使用广受欢迎的 ordered-float crate 提供的另一种解决方案,允许您使用内置的 Iterator::max 方法:
use ordered_float::NotNan; // 2.0.0

let max = arr
    .iter()
    .copied()
    .map(NotNan::new)
    .flatten() // ignore NAN values (errors from the previous line)
    .max()
    .map(NotNan::into_inner);

这基本上和你会写的寻找整数数组中最大值的惯用代码相同:

let max = arr.iter().copied().max();

区别在于它在每个值周围添加了一个NotNan包装器,该包装器实现了Ord。找到结果后,它会取消包装值以获取内部浮点数。您可以将此模式应用于大多数现有的使用整数的代码,以更新其以支持使用浮点数。


1

以下是一种使用实际向量且不进行复制操作的清晰方法:

fn main() {
    let v: Vec<f64> = vec![-2.2, -7.7, -3.3];
    let max = v
        .iter()
        .fold(f64::NEG_INFINITY, |prev, curr| prev.max(*curr));
    assert!(max == -2.2);
    println!("{}", max);
}

playground


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接