0
\$\begingroup\$

The following function is an attempt to generate powers of two below the input number max.

So powers_of_two_below(15u8, u8::BITS) generates 1, 2, 4, 8. It does calculate 16, but does not include it. This function avoids calculating powers that cause overflow by taking bits as input (since there doesn't appear to be a standard trait that exposes T::BITS). It can be re-used for several number types.

But it doesn't seem very concise. Can you recommend ways to improve it?

use num_traits::{One, Zero};
use std::ops::Shl;
pub fn powers_of_two_below<T>(max: T, bits: u32) -> impl Iterator<Item = T>
where
 T: Zero + One + PartialOrd + Shl<Output = T> + Copy,
{
 let mut exp = T::zero();
 (0..bits)
 .map(move |_| {
 let power = T::one() << exp;
 exp = exp + T::one();
 power
 })
 .take_while(move |&x| x < max)
}

I tried to make a more concise version:

pub fn powers_of_two_below<T>(max: T, bits: u32) -> impl Iterator<Item = T>
where
 T: One + PartialOrd + Shl<Output = T> + Copy + From<u32>,
{
 (0..bits)
 .map(|i| T::one() << i.into())
 .take_while(move |&x| x < max)
}

...but it is more impractical: A lot of number types don't have From<u32> (including usize and uN where N < 32).

asked Jan 24, 2022 at 0:30
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

By specifying the right hand side of Shl, you can remove the From<u32> entirely:

fn powers_of_two_below<T>(max: T, bits: u32) -> impl Iterator<Item = T>
where
 T: One + PartialOrd + Shl<u32, Output = T> + Copy,
{
 (0..bits)
 .map(|i: u32| T::one() << i)
 .take_while(move |&x| x < max)
}

If you wanted to remove the bits parameter, you'd probably have to implement your own trait specifically for it, but I'm not sure how you'd define bits for floating point numbers.

Here's an example where I defined a Bits trait, using a macro to implement it for all integer types. I also used it to replace num_traits::One because why not.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=cd4e4e7db8deb4c8be883c759dd906bf

answered Jan 27, 2022 at 17:53
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.