Sorting a Vec of f32 without ever panic!

Quoting: Sort a Vector - Rust Cookbook

fn main() {
    let mut vec = vec![1.1, 1.15, 5.5, 1.123, 2.0];

    vec.sort_by(|a, b| a.partial_cmp(b).unwrap());

    assert_eq!(vec, vec![1.1, 1.123, 1.15, 2.0, 5.5]);
}

This code has the slightly problematic issue that it might panic!(). I'm doing depth sorting in OpenGL. In the case of Nans / bad things, I'd prefer the Nans / ... to get pushed to one side (either front or back, I don't really care).

This is so it becomes a "visual glitch" rather than crashing the entire app.

Is there an idiomatic way to soft f32's in the above manner?

This appears to work:

fn f32_nans_last(a: f32, b: f32) -> std::cmp::Ordering {
    match a.partial_cmp(&b) {
        Some(ord) => ord,
        None => match (a.is_nan(), b.is_nan()) {
            (true, true) => std::cmp::Ordering::Equal,
            (true, _) => std::cmp::Ordering::Greater,
            (_, true) => std::cmp::Ordering::Less,
            (_, _) => std::cmp::Ordering::Equal, // should never happen
        },
    }
}

suggestions / warnings ?

2 Likes

You can use the OrderedFloat wrapper -- and since it's transparent, it should also be fine to cast an existing slice to that type for sorting.

2 Likes

Edit: This method avoids extra branching steps most of the time and is probably faster than mine. Though the same logic can and probably should still be put into a closure used with sort_unstable_by.

The sort_unstable_by method for slices—and Vecs by extension—is probably what you want. It seems like you don’t care about whether equal elements get reordered, which is what the “unstable” means. It’s usually better to prefer the _unstable versions since they don’t allocate. This sounds like it would be important for you if you’re running this sort in a hot loop in graphics code. Allocation is slow.

For your case, I think you could just modify that example a little like this.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.