# Maximum of two floating points numbers

Hello, just started with Rust and trying to learn some of the basics.

Consider this piece of code:

``````use std::cmp;
fn main() {
let a: f64 = 1.0;
let b: f64 = 2.0;
let c: f64 = cmp::max(a, b);  // << Compiler error
let d: f64 = a.max(b);  // <<< OK
println!("c: {}", c);
println!("d: {}", d);
}
``````

Playpen

I don't understand why `a.max(b)` is different from `cmp::max(a, b)`.

What is the "proper" translation of C++'s `std::max(a, b)` to Rust?

Thank you!

1 Like

Well, they are different because they are different functions. The `std::cmp::max` function requires the `Ord` trait, which is only implemented for types with a total ordering. Floats are not totally ordered because they have a value called NaN which does not fit in anywhere in the order, so you can't use this method with floats.

The `a.max(b)` function on the other hand is a function defined directly on the `f64` type. You can also call it as `f64::max(a, b)`.

2 Likes

If there is no total ordering good enough for `std::cmp::max`, then what does `f64::max` return? And why does a total order matter for comparison of two values?

The documentation says this:

Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs. This matches the behavior of libm’s fmin.

Basically, it treats NaN as the smallest possible value. However, `f64::min` treats NaN as the largest possible value. The order can't be inconsistent in this way with the functions in `std::cmp`.

1 Like

A total ordering is important because if the order is not total, the two values might be incomparable i.e. neither is smaller than the other, but they also are not equal, so there's no meaningful value to return.

1 Like

So you are saying `std::cmp::max` is in fact `std::max_total_order` and `f64::max` is in fact `f64::max_partial_order`?

I think it is great that Rust is very verbose about subtleties like that, but it is a bit confusing having two central functions with identical names doing something different..

Well, `f64::max` is not really a "max partial order". It is is specific to floats, and would not be usable with other partially ordered types.

Well, in this particular case it will not compile if you mix them up, so it's not a big problem in my opinion.

1 Like

Ok, thank you. So you say that C++'s `std::max(a, b)` translates to `a.max(b)` in Rust?

Then my question would be how do I translate this C++ code to Rust?

``````template <typename T>  // intended for float or double
T foo(T a, T b) {
return std::max(a, b) + T(1);
}
``````

My attempts failed because the `cmp::max` function requires an `Ord` trait which doesn't exist for `Float`, but based on your answer I don't know how to translate the `*.max(*)` form to a trait.

If you want generics over numeric types in Rust, you're looking for num-traits — Rust math library // Lib.rs

Note, also, that there's two good ways to interpret "maximum" for floating point -- both of which are (or were) in IEEE 754. There's also `f64::maximum` in nightly now. That difference -- which doesn't exist for `Ord` types -- is a big part of why there's no `Ord::max` for floats.

1 Like

Ok, I see .. This seems to work:

``````fn foo<T: Float>(a: T, b: T) {
return a.max(b) + ...;
}
``````

Then last question: What does Float::Max return for the pathological cases? Is it documented somewhere?

Actually found it in the source: Float::Max uses f32/64::max and for that the docs say

Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs. This matches the behavior of libm’s fmin.

Which I guess is a typo Thank you all for your help!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.