rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.29k stars 12.72k forks source link

Implement `signum()` on unsigned integers #71728

Open jhpratt opened 4 years ago

jhpratt commented 4 years ago

This can be quite useful when writing macros that are generic over any integer.

For example, I just tried writing this code (bar is any of i8, i16, i32, u8, u16, u32 via a macro)

match (foo.signum(), bar.signum()) {
    (1, 1) | (-1, -1) => max,
    (-1, 1) | (1, -1) => min,
    _ => zero,
}

But because u*::signum isn't implemented, I had to resort to something far more verbose:

if foo > 0 {
    if bar > 0 {
        max
    }
    else if bar < 0 {
        min
    }
    else {
        zero
    }
} else if foo < 0 {
    if bar > 0 {
        min
    }
    else if bar < 0 {
        max
    }
    else {
        zero
    }
} else {
    zero
}

This can be simplified a bit, but at the expense of performing the operations more than once. This might be optimized away, though.

if (foo > 0 && bar > 0) || (foo < 0 && bar < 0) {
    max
} else if (foo > 0 && bar < 0) || (foo < 0 && bar > 0) {
    min
} else {
    zero
}

To allow for the first example to compile (along with the rest of the code, of course), I'd think having u32::signum return i32 would make sense, despite returning -1 being impossible. I definitely think using signum makes things clearer and more readable.

If this is something that is desired, I can submit a PR.

est31 commented 4 years ago

You can do:

match (foo > 0, bar > 0) {
    (true, true) | (false, false) => max,
    (false, true) | (true, false) => min,
    _ => zero,
}

if you want to treat 0 specially, you can also do foo.cmp(&0) and match on that.

jhpratt commented 4 years ago

@est31 I'd definitely match on > 0 if it were only on unsigned integers. As I had said, though, it is used in a macro that is generic.

I could use .cmp(&0), I suppose. I just think having parity between various integer types makes more sense.

est31 commented 4 years ago

Also note that matching on signum values doesn't work on float values. Matching on partial_cmp results is most portable.