Reputation: 183
I'm solving a little math problem called the Syracuse problem (3n+1 problem).
Thing is i want my function to work for 2 types, one is u64 the other is a struct that extends the size of u64 by containing 2 u64 that i called U128.
my u64 function looks like this
fn syracuse(n: u64) -> u64 {
match n % 2 {
0 => n / 2,
1 => 3 * n + 1,
_ => 1,
}
}
I've tried implementing a trait to my U128 and u64.
fn syracuse<T>(n: T) -> T where T : Add +Mul+Div+Rem + Basic0123 {
match n % Basic0123::two() {
Basic0123::zero() => n / Basic0123::two(),
Basic0123::one() => Basic0123::three() * n + Basic0123::one(),
_ => Basic0123::one(),
}
}
It doesn't compile, the pattern matching doesn't like this. I'm new to rust and i'm trying to understand if creating a function with generic typing is okay for this problem that only treats 2 different types the DRY way or i should just stick with simply rewriting the function for the U128 type?
Upvotes: 0
Views: 572
Reputation: 19672
I'm just going to assume most of the stuff in the comments has been dealt with and you're back to using the std::u128
primitive type rather than your own.
The proper way to implement the Syracuse conjecture on a generic type is as follows:
fn syracuse<T>(n: T) -> T
where T : Copy + Eq + Add<Output = T> + Mul<Output = T> + Div<Output = T> + Rem<Output = T> + From<u32> {
let zero:T = 0.into();
match n % 2.into() == zero {
true => n/(2.into()),
false => n * (3.into()) + 1.into()
}
}
In order of appearance:
Copy
is required because we did not require Rem
on &T
, but on T
Output
type specifications are so we do not implicitly change type - an operation on T
will always map to T
Eq
so we can compare the result of the remainderFrom<u32>
so we can into()
every single numerical constantA working version can be found here
Upvotes: 2