1

I am trying to create a generic function as below:

use std::ops::Add;
use std::ops::DivAssign;

fn normalize<T>(vec: &mut Vec<Vec<T>>, bd: u32)
where
    T: DivAssign + Add<Output = T> + From<i32> + From<i16>,
{
    let max_value = match bd {
        16 => T::from(i16::MAX) + T::from(1_i16),
        32 => T::from(i32::MAX) + T::from(1_i32),
        _ => panic!("unsuported bit depth"),
    };

    for ch in 0..vec.len() {
        vec[ch].iter_mut().for_each(|x| *x /= max_value);
    }
}

When I call the function I am getting an error:

normalize::<f32>(&mut vec![vec![1_f32,2_f32,3_f32]], 16_u32);

the trait bound `f32: From<i32>` is not satisfied
the following implementations were found:
  <f32 as From<i16>>
  <f32 as From<i8>>
  <f32 as From<u16>>
  <f32 as From<u8>>rustcE0277
misc.rs(19, 38): required by a bound in `normalize`

Could someone explain me what's going on and how can I fix it?

daniellga
  • 1,142
  • 6
  • 16
  • For `i32` maybe use `as i32`, reference https://stackoverflow.com/a/47331819/4366445 – rustyhu Nov 12 '21 at 03:33
  • Have you looked at the multitude of [matrix and linear algebra crates](https://crates.io/keywords/matrix) such as [ndarray](https://crates.io/crates/ndarray)? You could use one and save yourself some headaches! – John Kugelman Nov 12 '21 at 03:41
  • Sure I have! I am trying to learn Rust, so it's not a headache in this case. I just want to understand what's going on and how I can overcome this without taking easier paths. – daniellga Nov 12 '21 at 03:57
  • 1
    I gotcha. Take a look at [num_traits](https://crates.io/crates/num-traits), then. It adds a whole bunch of traits to make it easier to write generic code over integer types. I understand the desire to not lean on third party libraries, yet I want to encourage you to be open to using some of them. There are a lot of "standard library adjacent" crates written by rust-lang folks. The libs team is cautious about putting too much into std and leaves a lot of functionality to community crates. num_traits is a good example of this. – John Kugelman Nov 12 '21 at 04:24
  • 1
    It handles a lot of drudgery for you, and there's a lot of that when you want to be generic over primitive types. – John Kugelman Nov 12 '21 at 04:27

1 Answers1

1

From is only available when conversions are lossless.

Single-precision floats have a 23-bit significand. They can only represent the full integer range from 0 to 224. Any higher than that and there are integers that can't be represented.

Demonstration:

println!("{} as f32 = {}", 16777213i32, 16777213i32 as f32); // 2**24 - 3
println!("{} as f32 = {}", 16777214i32, 16777214i32 as f32); // 2**24 - 2
println!("{} as f32 = {}", 16777215i32, 16777215i32 as f32); // 2**24 - 1
println!("{} as f32 = {}", 16777216i32, 16777216i32 as f32); // 2**24
println!("{} as f32 = {}", 16777217i32, 16777217i32 as f32); // 2**24 + 1
println!("{} as f32 = {}", 16777218i32, 16777218i32 as f32); // 2**24 + 2
println!("{} as f32 = {}", 16777219i32, 16777219i32 as f32); // 2**24 + 3

Output:

16777213 as f32 = 16777213
16777214 as f32 = 16777214
16777215 as f32 = 16777215
16777216 as f32 = 16777216
16777217 as f32 = 16777216
16777218 as f32 = 16777218
16777219 as f32 = 16777220

Playground

John Kugelman
  • 349,597
  • 67
  • 533
  • 578