One very easy way to take the addition modulo of 2 numbers is to cast them to u128 like this, so I avoid overflow and implement it for all unsigned integers u8, u16, u32, u64
:
pub fn modulo_add<T: Into<u64>, U: Into<u64>, M: Into<u64>>(t: T, u: T, m: M) -> u64{
((t.into() as u128 + u.into() as u128) % m.into() as u128) as u64
}
What if I wanted to be REALLY generic over the types being moduled out? Not only for unsigned integers convertible to u64
but any type?
Well, of course I could do this:
pub fn modulo_add<T: core::ops::Add<Output=M>, U, M: core::ops::Rem<Output=M> + TryInto<R>, R>(t: T, u: T, m: M) -> R{
((t+u)%m).try_into().ok().unwrap()
}
but now I'm not avoiding overflow, because if T=U=u64
, then adding u64::MAX
with u64::MAX
would give overflow and thus the mod would not work.
Ideally on C++ I'd implement the addition for u8 and make it cast to u16, and the u16 to cast to u32, and u64 to u128, but on Rust you cannot have specialization of functions for each type.
Also, maybe I have a really fast hardware implementation for u64 only. Or I want to do it differently depending on the type.
What would be a good solution here?