Converting usize into f32

Viewed 1997

I have implemented the following function that calculates the mean of a sequence:

fn mean<T, R>(seq: &[T]) -> R
    where R: Div<R, Output=R> + From<T> + From<usize> + Sum<R>
{
    let total: R = seq.iter().map(|&x| R::from(x)).sum()
    let size = R::from(seq.len())
    total / size
}

However, I'm having trouble when converting the usize that is returned from seq.len()

let numbers = vec![10, 20, 30, 40, 50, 60];
let result: f32 = mean(&numbers);
println!("{:?}", result);
5  | fn mean<T, R>(seq: &[T]) -> R
   |    ----
6  |     where R: Div<R, Output=R> + From<T> + From<usize> + Sum<R>
   |                                           ----------- required by this bound in `mean`
...
15 |     let result: f32 = mean(&numbers);
   |                       ^^^^ the trait `std::convert::From<usize>` is not implemented for `f32`

I'm quite blocked by this since I'm still a beginner with traits. How can I solve this specific problem? (if it can be done)

2 Answers

It is not possible to represent every possible i32 value in f32 format. That's the reason why From trait implementation provided for f32 supports only i16/u16/i8/u8.

i32 and f32 have the same amount of bytes but usually f32 spent few bytes for exponent so it can't represent all numbers from i32. Single-precision floating-point format

The problem is that f32 does not implement From<usize>. It does implement From<i16>, From<i8>, From<u16> and From<u8>. This is becausef32` cannot represent all the values of a bigger integer exactly.

What you probably want is to use the as conversion, that allows for some precision loss. Unfortunately you cannot use as on generic types, only on primitive types.

You could write a trait to do all the necessary as conversions manually... But of course there is a crate for that! With num_traits::cast::AsPrimititve your code becomes:

fn mean<T, R>(seq: &[T]) -> R
    where R: Div<R, Output=R> + Sum<R> + Copy + 'static,
          T: AsPrimitive<R>,
          usize: AsPrimitive<R>
{
    let total: R = seq.iter().map(|&x| x.as_()).sum();
    let size = seq.len().as_();
    total / size
}

I have added the Copy constraints, that I think you missed in your code, and also the 'static for R that is required for AsPrimitive.

Related