Generics: how to test if negative

I'm practicing some Rust by going through Numerical Recipes, but I'm not getting very far because I don't understand how to work with generic types. Here's the function I'm trying to implement.

/// Return a value with the magnitude of `a` and and the sign of `b`
pub fn sign<T>(a: T, b: T) -> T
    where T: PartialOrd + std::ops::Neg<Output = T>,
{
    if b >= 0 {
        if a >= 0 {
            a
        } else {
            -a
        }
    } else {
        if a >= 0 {
            -a
        } else {
            a
        }
    }
}

This doesn't work because 0 is an integer and not a T. What's the right way to do this?

I'm not familiar with this "Numerical Recipes" thing, but using generic integers is generally rather cumbersome in Rust. I would recommend just picking an integer type and using that.

The num_traits crate has traits for working with generic number types. I believe you could use a num_traits::Num bound to get the comparison to zero, though you'd have to rewrite it slightly so you aren't using a 0 literal.

Technically you can get a zero with just std

pub fn zero<T: std::iter::Sum>() -> T { std::iter::empty().sum() }

But yes, num_traits is the way to go if you really want to do generic math.

1 Like

Thanks for the help. I was able to get it to work with num_traits like this...

use num_traits::{self, Signed};


/// Return a value with the magnitude of `a` and and the sign of `b`
pub fn sign<T>(a: T, b: T) -> T
    where T: PartialOrd + Signed,
{
    if b.is_positive() {
        if a.is_positive() {
            a
        } else {
            -a
        }
    } else {
        if a.is_positive(){
            -a
        } else {
            a
        }
    }
}
pub fn sign<T: Signed>(a: T, b: T) -> T {
    if a.is_positive() == b.is_positive() {
        a
    } else {
        -a
    }
}

(Also check what you want to happen with 0s, maybe you want is_negative.)

1 Like

I think the most literal translation of your original code would be

pub fn sign<T>(a: T, b: T) -> T
where
    T: PartialOrd + std::ops::Neg<Output = T> + num_traits::Num,
{
    if b >= T::zero() {
        if a >= T::zero() {
            a
        } else {
            -a
        }
    } else {
        if a >= T::zero() {
            -a
        } else {
            a
        }
    }
}
1 Like

I'd write it like this, which doesn't need any constants like 0:

pub fn sign<T>(a: T, b: T) -> T
where
    T: Signed,
{
    b.signum() * a.abs()
}

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.