Search code examples
sortingrustfloating-point

How can I sort a vector of floats in Rust?


If I have a couple of floating-point numbers and try to sort them like this:

fn main() {
    let mut nums: Vec<f64> = vec![0.53, 3.18, 4.783, 9.0, -1.2, 0.0];
    nums.sort();
    println!("{:?}", nums);
}

I get a compile error: "the trait bound f64: Ord is not satisfied".

How can I sort these numbers?


Solution

  • TLDR: do

    nums.sort_by(f64::total_cmp);
    

    The basic reason why Rust doesn't let you sort floating-point numbers is that NaN is weird. All comparisons involving a NaN return false, which can cause sorting algorithms to break (this is an issue in Python, for example). There's also the strange case of zero and negative zero, which are equal yet have different representations. Since Rust's design philosophy revolves around handling errors explicitly, you cannot use the sort() method on floats.

    However, IEEE 754 does define a way to sort floating-point numbers which can handle any kind of NaN (there are many bit patterns which represent a NaN). The order is:

    • NaN (negative sign bit), in descending order of the significand bits
    • Negative infinity
    • All the negative numbers, in mathematical order
    • Negative zero
    • Positive zero
    • All the positive numbers, in mathematical order
    • Positive infinity
    • NaN (positive sign bit), in ascending order of the significand bits

    To get this ordering, Rust offers the total_cmp method between all the float types. Therefore, your code can be fixed by doing:

    fn main() {
        let mut nums: Vec<f64> = vec![0.53, 3.18, 4.783, 9.0, -1.2, 0.0];
        nums.sort_by(f64::total_cmp);
        println!("{:?}", nums);
    }
    

    (playground link)

    Addendum

    There are two alternatives that might be better for certain use cases:

    nums.sort_unstable_by(f64::total_cmp);
    

    sort_unstable_by uses a different sorting algorithm that is likely faster than the standard one, but you should benchmark your application to make sure (relevant issue).

    #![feature(sort_floats)] // requires nightly toolchain
    
    nums.sort_floats();
    

    sort_floats is the same as the above but has not yet been stabilized.