Generic function compare Integer and Float with 0

Hi, I tried to write a generic function to compare all Integer and Float with 0, but compile failed. Any suggestion? Thanks!

fn eq_zero<T: std::cmp::PartialEq>(a:T) -> bool {
    if a == 0 {
        true
    } else {
        false
    }
}

fn main() {
    println!("{}",eq_zero(0) );
    println!("{}",eq_zero(0.0) );
}
error[E0308]: mismatched types
 --> src\main.rs:2:13
  |
1 | fn eq_zero<T: std::cmp::PartialEq>(a:T) -> bool {
  |            - this type parameter
2 |     if a == 0 {
  |             ^ expected type parameter `T`, found integer
  |
  = note: expected type parameter `T`
                       found type `{integer}`

When you write 0 that's actually an i32 constant, and because your function requires T: PartialEq (i.e. T is only comparable with itself) you get a type mismatch error.

rustc is effectively saying

You've written a function which accepts any arbitrary T which can be compared for equality with another T but now you are trying to compare it with a i32, that doesn't make sense.

How you implement this is by letting the type system know what "zero" means for your particular T.

trait Zero {
  const ZERO: Self;
}

impl Zero for i32 { const ZERO: Self = 0; }
impl Zero for f32 { const ZERO: Self = 0.0; }

Then you can update the function to accept any type which is comparable with itself (PartialEq) and has a zero value (Zero).

pub fn is_zero<T>(value: T) -> bool
where
    T: PartialEq + Zero,
{
    value == T::ZERO
}

This also lets you extend the is_zero() function to work with more than just primitive numbers. For example:

fn main() {
    assert_eq!(is_zero(Point::new(3.14, 42.0)), false);
    assert_eq!(is_zero(Point::new(0.0, 0.0)), true);
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Point {
    x: f32,
    y: f32,
}

impl Point {
    pub const fn new(x: f32, y: f32) -> Self {
        Point { x, y }
    }
}

impl Zero for Point {
    const ZERO: Self = Point::new(0.0, 0.0);
}

(playground)

1 Like

0 is not a floating point value. You would need '0.0'

Which is a good reminder that it is generally a bad idea to compare floating point values for equality. Very often things that you think should be equal are not.

1 Like

In IEEE754 floating point arithmetics, 0 is not equals to -0. No, I remembered it wrong.
They're not identical, but considered equals.
Also 0.1 + 0.2 - 0.3 is not zero.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=871e85f6e8d5b2fea767459685f4fc89

1 Like

Thank you!