2024-09-02 23:15:17 +00:00
|
|
|
#[derive(Clone,Copy,Debug,Hash)]
|
|
|
|
pub struct Ratio<Num,Den>{
|
2024-09-10 20:04:43 +00:00
|
|
|
pub num:Num,
|
|
|
|
pub den:Den,
|
2024-09-02 23:15:17 +00:00
|
|
|
}
|
|
|
|
impl<Num,Den> Ratio<Num,Den>{
|
2024-09-10 20:04:43 +00:00
|
|
|
#[inline(always)]
|
2024-09-02 23:15:17 +00:00
|
|
|
pub const fn new(num:Num,den:Den)->Self{
|
|
|
|
Self{num,den}
|
|
|
|
}
|
|
|
|
}
|
2024-09-10 20:04:43 +00:00
|
|
|
|
2024-09-11 19:59:33 +00:00
|
|
|
/// The actual divide implementation, Div is replaced with a Ratio constructor
|
|
|
|
pub trait Divide<Rhs=Self>{
|
|
|
|
type Output;
|
|
|
|
fn divide(self,rhs:Rhs)->Self::Output;
|
|
|
|
}
|
|
|
|
|
2024-09-10 20:04:43 +00:00
|
|
|
impl<Num,Den> Ratio<Num,Den>
|
|
|
|
where
|
2024-09-11 19:59:33 +00:00
|
|
|
Num:Divide<Den>,
|
2024-09-10 20:04:43 +00:00
|
|
|
{
|
|
|
|
#[inline]
|
2024-09-11 19:59:33 +00:00
|
|
|
pub fn divide(self)-><Num as Divide<Den>>::Output{
|
|
|
|
self.num.divide(self.den)
|
2024-09-10 20:04:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//take care to use the ratio methods to avoid nested ratios
|
|
|
|
|
|
|
|
impl<LhsNum,LhsDen> Ratio<LhsNum,LhsDen>{
|
|
|
|
#[inline]
|
|
|
|
pub fn mul_ratio<RhsNum,RhsDen>(self,rhs:Ratio<RhsNum,RhsDen>)->Ratio<<LhsNum as core::ops::Mul<RhsNum>>::Output,<LhsDen as core::ops::Mul<RhsDen>>::Output>
|
|
|
|
where
|
|
|
|
LhsNum:core::ops::Mul<RhsNum>,
|
|
|
|
LhsDen:core::ops::Mul<RhsDen>,
|
|
|
|
{
|
|
|
|
Ratio::new(self.num*rhs.num,self.den*rhs.den)
|
|
|
|
}
|
|
|
|
#[inline]
|
|
|
|
pub fn div_ratio<RhsNum,RhsDen>(self,rhs:Ratio<RhsNum,RhsDen>)->Ratio<<LhsNum as core::ops::Mul<RhsDen>>::Output,<LhsDen as core::ops::Mul<RhsNum>>::Output>
|
|
|
|
where
|
|
|
|
LhsNum:core::ops::Mul<RhsDen>,
|
|
|
|
LhsDen:core::ops::Mul<RhsNum>,
|
|
|
|
{
|
|
|
|
Ratio::new(self.num*rhs.den,self.den*rhs.num)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
macro_rules! impl_ratio_method {
|
|
|
|
($trait:ident, $method:ident, $ratio_method:ident) => {
|
|
|
|
impl<LhsNum,LhsDen> Ratio<LhsNum,LhsDen>{
|
|
|
|
#[inline]
|
|
|
|
pub fn $ratio_method<RhsNum,RhsDen,LhsCrossMul,RhsCrossMul>(self,rhs:Ratio<RhsNum,RhsDen>)->Ratio<<LhsCrossMul as core::ops::$trait<RhsCrossMul>>::Output,<LhsDen as core::ops::Mul<RhsDen>>::Output>
|
|
|
|
where
|
|
|
|
LhsNum:core::ops::Mul<RhsDen,Output=LhsCrossMul>,
|
|
|
|
LhsDen:core::ops::Mul<RhsNum,Output=RhsCrossMul>,
|
|
|
|
LhsDen:core::ops::Mul<RhsDen>,
|
|
|
|
LhsDen:Copy,
|
|
|
|
RhsDen:Copy,
|
|
|
|
LhsCrossMul:core::ops::$trait<RhsCrossMul>,
|
|
|
|
{
|
|
|
|
Ratio::new((self.num*rhs.den).$method(self.den*rhs.num),self.den*rhs.den)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
impl_ratio_method!(Add,add,add_ratio);
|
|
|
|
impl_ratio_method!(Sub,sub,sub_ratio);
|
|
|
|
impl_ratio_method!(Rem,rem,rem_ratio);
|
|
|
|
|
|
|
|
/* generic rhs mul is not possible!
|
|
|
|
impl<Lhs,RhsNum,RhsDen> core::ops::Mul<Ratio<RhsNum,RhsDen>> for Lhs
|
|
|
|
where
|
|
|
|
Lhs:core::ops::Mul<RhsNum>,
|
|
|
|
{
|
|
|
|
type Output=Ratio<<Lhs as core::ops::Mul<RhsNum>>::Output,RhsDen>;
|
|
|
|
#[inline]
|
|
|
|
fn mul(self,rhs:Ratio<RhsNum,RhsDen>)->Self::Output{
|
|
|
|
Ratio::new(self*rhs.num,rhs.den)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
//operators
|
|
|
|
|
|
|
|
impl<LhsNum,LhsDen> core::ops::Neg for Ratio<LhsNum,LhsDen>
|
|
|
|
where
|
|
|
|
LhsNum:core::ops::Neg,
|
|
|
|
{
|
|
|
|
type Output=Ratio<<LhsNum as core::ops::Neg>::Output,LhsDen>;
|
|
|
|
#[inline]
|
|
|
|
fn neg(self)->Self::Output{
|
|
|
|
Ratio::new(-self.num,self.den)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl<LhsNum,LhsDen,Rhs> core::ops::Mul<Rhs> for Ratio<LhsNum,LhsDen>
|
|
|
|
where
|
|
|
|
LhsNum:core::ops::Mul<Rhs>,
|
|
|
|
{
|
|
|
|
type Output=Ratio<<LhsNum as core::ops::Mul<Rhs>>::Output,LhsDen>;
|
|
|
|
#[inline]
|
|
|
|
fn mul(self,rhs:Rhs)->Self::Output{
|
|
|
|
Ratio::new(self.num*rhs,self.den)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl<LhsNum,LhsDen,Rhs> core::ops::Div<Rhs> for Ratio<LhsNum,LhsDen>
|
|
|
|
where
|
|
|
|
LhsDen:core::ops::Mul<Rhs>,
|
|
|
|
{
|
|
|
|
type Output=Ratio<LhsNum,<LhsDen as core::ops::Mul<Rhs>>::Output>;
|
|
|
|
#[inline]
|
|
|
|
fn div(self,rhs:Rhs)->Self::Output{
|
|
|
|
Ratio::new(self.num,self.den*rhs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! impl_ratio_operator {
|
|
|
|
($trait:ident, $method:ident) => {
|
|
|
|
impl<LhsNum,LhsDen,Rhs,Intermediate> core::ops::$trait<Rhs> for Ratio<LhsNum,LhsDen>
|
|
|
|
where
|
|
|
|
LhsNum:core::ops::$trait<Intermediate>,
|
|
|
|
LhsDen:Copy,
|
|
|
|
Rhs:core::ops::Mul<LhsDen,Output=Intermediate>,
|
|
|
|
{
|
|
|
|
type Output=Ratio<<LhsNum as core::ops::$trait<Intermediate>>::Output,LhsDen>;
|
|
|
|
#[inline]
|
|
|
|
fn $method(self,rhs:Rhs)->Self::Output{
|
|
|
|
Ratio::new(self.num.$method(rhs*self.den),self.den)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_ratio_operator!(Add,add);
|
|
|
|
impl_ratio_operator!(Sub,sub);
|
|
|
|
impl_ratio_operator!(Rem,rem);
|
|
|
|
|
|
|
|
//assign operators
|
|
|
|
|
|
|
|
impl<LhsNum,LhsDen,Rhs> core::ops::MulAssign<Rhs> for Ratio<LhsNum,LhsDen>
|
|
|
|
where
|
|
|
|
LhsNum:core::ops::MulAssign<Rhs>,
|
|
|
|
{
|
|
|
|
#[inline]
|
|
|
|
fn mul_assign(&mut self,rhs:Rhs){
|
|
|
|
self.num*=rhs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl<LhsNum,LhsDen,Rhs> core::ops::DivAssign<Rhs> for Ratio<LhsNum,LhsDen>
|
|
|
|
where
|
|
|
|
LhsDen:core::ops::MulAssign<Rhs>,
|
|
|
|
{
|
|
|
|
#[inline]
|
|
|
|
fn div_assign(&mut self,rhs:Rhs){
|
|
|
|
self.den*=rhs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! impl_ratio_assign_operator {
|
|
|
|
($trait:ident, $method:ident) => {
|
|
|
|
impl<LhsNum,LhsDen,Rhs> core::ops::$trait<Rhs> for Ratio<LhsNum,LhsDen>
|
|
|
|
where
|
|
|
|
LhsNum:core::ops::$trait,
|
|
|
|
LhsDen:Copy,
|
|
|
|
Rhs:core::ops::Mul<LhsDen,Output=LhsNum>,
|
|
|
|
{
|
|
|
|
#[inline]
|
|
|
|
fn $method(&mut self,rhs:Rhs){
|
|
|
|
self.num.$method(rhs*self.den)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_ratio_assign_operator!(AddAssign,add_assign);
|
|
|
|
impl_ratio_assign_operator!(SubAssign,sub_assign);
|
|
|
|
impl_ratio_assign_operator!(RemAssign,rem_assign);
|