Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I sort `NaN` so that it is greater than any other number, and equal to any other `NaN`?

I'm sorting a vector based on two criteria. The first is a floating point that can be NaN, the second is a string which is used to break ties lexicographically.

vec.sort_by(|a, b| {
    match (foo(a) as f64 / bar(a) as f64).partial_cmp(&(foo(b) as f64 / bar(b) as f64)) {
        Some(x) => {
            Ordering::Equal => name(a).cmp(name(b)),
            other => other,
        }
        None() => {
            //Not sure what to put here.
        }
    }
}

foo(a) returns int > 0, bar(a) returns int >= 0, name(a) returns & String.

How do I sort NaN so that it is greater than any other number, and equal to any other NaN (lexicographic tie-breaker)?

like image 342
HiDefender Avatar asked Oct 28 '25 14:10

HiDefender


1 Answers

You already know how to handle ties, all you need is to compare floating point in the desired way. Just... write the code that you described:

use std::cmp::Ordering;
use std::f32;

fn main() {
    let mut vec = [91.0, f32::NAN, 42.0]; 

    vec.sort_by(|&a, &b| {
        match (a.is_nan(), b.is_nan()) {
            (true, true) => Ordering::Equal,
            (true, false) => Ordering::Greater,
            (false, true) => Ordering::Less,
            (false, false) => a.partial_cmp(&b).unwrap(),
        }
    });

    println!("{:?}", vec);
}

You could be fancy and wrap that up in a structure that represents the key as well:

use std::cmp::Ordering;
use std::f32;

fn main() {
    let mut vec = [91.0, f32::NAN, 42.0];

    vec.sort_by_key(|&a| MyNanKey(a));

    println!("{:?}", vec);
}

#[derive(Debug, Copy, Clone, PartialEq)]
struct MyNanKey(f32);

impl Eq for MyNanKey {}

impl PartialOrd for MyNanKey {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for MyNanKey {
    fn cmp(&self, other: &Self) -> Ordering {
        match (self.0.is_nan(), other.0.is_nan()) {
            (true, true) => Ordering::Equal,
            (true, false) => Ordering::Greater,
            (false, true) => Ordering::Less,
            (false, false) => self.0.partial_cmp(&other.0).unwrap(),
        }
    }
}

I did no thinking about if this would be applicable for the various infinities or denormalized floating point values, so beware.

like image 115
Shepmaster Avatar answered Oct 30 '25 06:10

Shepmaster



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!