I'm trying to do some basic numerical calculations, but I want to be able to do them irrespective of what numeric type is in use. Specifically, I want these functions to work with either usize
or BigUint
(from the num
crate), and I thought the easiest way to do that would be to create functions with type parameters. Here are the functions as I would like to have them work:
use std::ops::{Add, Mul, Div, Rem};
use std::default::Default;
/// Performs a Horner encoding on the given elements.
pub fn horner<T>(elems: &Vec<T>, alg_sizes: &Vec<T>) -> T
where T: Default + Add<T,Output=T> + Mul<T,Output=T> {
let k = elems.len();
let mut ans: T = Default::default();
for i in (0..k).rev() {
ans = alg_sizes[i]*ans+elems[i];
}
ans
}
/// Inverts a Horner encoding on the given elements.
pub fn horner_inv<T>(i: T, alg_sizes: &Vec<T>) -> Vec<T>
where T: Default + Clone + Div<T,Output=T> + Rem<T,Output=T> {
let mut ans = vec![Default::default();alg_sizes.len()];
let mut rem = i.clone();
for j in 0..alg_sizes.len() {
ans[j] = rem % alg_sizes[j];
rem = rem / alg_sizes[j];
}
ans
}
/// Performs a Horner encoding on the given elements.
pub fn horner_power<T>(elems: &Vec<T>, alg_size: T) -> T
where T: Default + Add<T,Output=T> + Mul<T,Output=T> {
let k = elems.len();
let mut ans: T = Default::default();
for i in (0..k).rev() {
ans = alg_size*ans + elems[i];
}
ans
}
/// Inverts a Horner encoding on the given element.
pub fn horner_power_inv<T>(i: T, alg_size: T, power: usize) -> Vec<T>
where T: Default + Clone + Div<T,Output=T> + Rem<T,Output=T> {
let mut ans = vec![Default::default();power];
let mut rem = i.clone();
for j in 0..power {
ans[j] = rem % alg_size;
rem = rem / alg_size;
}
ans
}
Unfortunately, when I try to compile literally this, I get a lot of movement errors. (Note: BigUint
is not Copy
, so I can't rely on Copy
semantics here - these functions work fine if I require T
to be Copy
in each function declaration.) Naturally then, I try to use references instead of literal values, but that requires me to write function signatures like:
pub fn horner<'a,'b,T>(elems: &'b Vec<T>, alg_sizes: &'a Vec<T>) -> T
where T: Default + Add<&'b T,Output=T>,
&'a T: Mul<T,Output=T>
and I still get various move errors and complaints from the compiler about values not living long enough. I think that the problem lies with being unable to say something like where &'c T: Mul<&'d T,Output=T>
where 'c
and 'd
are allowed to refer to lifetimes within the scope of the function's execution itself.
Any suggestions how I could solve this difficulty?