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?

5
  • For i32 maybe use as i32, reference stackoverflow.com/a/47331819/4366445 Commented Nov 12, 2021 at 3:33
  • Have you looked at the multitude of matrix and linear algebra crates such as ndarray? You could use one and save yourself some headaches! Commented Nov 12, 2021 at 3: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. Commented Nov 12, 2021 at 3:57
  • 1
    I gotcha. Take a look at 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. Commented Nov 12, 2021 at 4: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. Commented Nov 12, 2021 at 4:27

1 Answer 1

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

Sign up to request clarification or add additional context in comments.

1 Comment

Any workaround for this in my example? To make it only work when there's no error in the conversion...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.