Cannot use floats in generic parameter where T: TryFrom<usize>

I am writing a function in a trait that is a supertrait of IntoIterator to work on collections of numbers like Vec and HashSet. It will find the mean of the collection.

I have currently

pub trait Stats: IntoIterator + Clone {
    fn sum(&self) -> Self::Item
    where
        Self::Item: Sum,
    {
        self.clone().into_iter().sum()
    }

    fn count(&self) -> usize {
        self.clone().into_iter().count()
    }

    fn mean(&self) -> Self::Item
    where
        Self::Item: Sum + TryFrom<usize> + Div<Self::Item, Output = Self::Item>,
    {
        self.sum()
            / match self.count().try_into() {
                Ok(v) => v,
                Err(_) => panic!("Cannot convert count to item type"),
            }
    }
}
impl<T> Stats for T where T: IntoIterator + Clone;

It works fine for integer types, but trying to run

let v: Vec<f64> = vec![1.0, 2.0, 3.0];
assert_eq!(v.mean(), 2.0);

(yes I know that it might be 2.000000000000000000004 or whatever but this'll do for now)
the compiler complains

error[E0277]: the trait bound `f64: From<usize>` is not satisfied
   --> src/lib.rs:143:22
    |
143 |         assert_eq!(v.mean(), 2.0);
    |                      ^^^^ the trait `From<usize>` is not implemented for `f64`
    |
    = help: the following other types implement trait `From<T>`:
              <f32 as From<i16>>
              <f32 as From<i8>>
              <f32 as From<u16>>
              <f32 as From<u8>>
              <f64 as From<f32>>
              <f64 as From<i16>>
              <f64 as From<i32>>
              <f64 as From<i8>>
            and 67 others
    = note: required because of the requirements on the impl of `Into<f64>` for `usize`
    = note: required because of the requirements on the impl of `TryFrom<usize>` for `f64`
note: required by a bound in `Stats::mean`
   --> src/lib.rs:73:27
    |
71  |     fn mean(&self) -> Self::Item
    |        ---- required by a bound in this
72  |     where
73  |         Self::Item: Sum + TryFrom<usize> + Div<Self::Item, Output = Self::Item>,
    |                           ^^^^^^^^^^^^^^ required by this bound in `Stats::mean`

It seems to me that f64 ought to implement TryFrom<usize>, because afaik there aren't any values of usize that aren't representable by an f64

If usize is 64 bits wide, then anything above 2^53 will be irrepresentable exactly even as an f64.

If you want to tolerate precision loss and rounding, you might want to look into num-traits.

1 Like

There are many on 64-bit platforms; f64 can only represent up to 52-bit integers exactly. Of course, fallible conversions are exactly what TryFrom/Into is for, but currently Rust doesn't implement TryFrom for any float/int combinations because of questions whether the need for exact float<->int conversions is common enough a need to warrant a TryFrom impl rather than possibly a named method. And a non-exact (with some arbitrary rounding mode) TryFrom doesn't sound like good idea either.

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.