use crate::numeric::{CastInto, FloatingPoint, Numeric, UnsignedInteger};
pub trait IntoTorus<F>: Sized
where
F: FloatingPoint,
Self: UnsignedInteger,
{
fn into_torus(self) -> F;
}
pub trait FromTorus<F>: Sized
where
F: FloatingPoint,
Self: UnsignedInteger,
{
fn from_torus(input: F) -> Self;
}
macro_rules! implement {
($Type: tt) => {
impl<F> IntoTorus<F> for $Type
where
F: FloatingPoint + CastInto<Self>,
Self: CastInto<F>,
{
fn into_torus(self) -> F {
let self_f: F = self.cast_into();
return self_f * (F::TWO.powi(-(<Self as Numeric>::BITS as i32)));
}
}
impl<F> FromTorus<F> for $Type
where
F: FloatingPoint + CastInto<Self>,
Self: CastInto<F>,
{
fn from_torus(input: F) -> Self {
let mut fract = input - F::floor(input);
fract *= F::TWO.powi(<Self as Numeric>::BITS as i32);
let carry = fract - F::floor(fract);
let zero_point_five = F::ONE / F::TWO;
if carry >= zero_point_five {
fract += F::ONE;
};
return fract.cast_into();
}
}
};
}
implement!(u8);
implement!(u16);
implement!(u32);
implement!(u64);
implement!(u128);