#[cfg(test)]
mod tests;
use numext_fixed_uint::U256;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::fmt;
use std::ops::{Add, Div, Mul, Sub};
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct RationalU256 {
numer: U256,
denom: U256,
}
impl fmt::Display for RationalU256 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}/{}", self.numer, self.denom)
}
}
impl RationalU256 {
#[inline]
pub fn new(numer: U256, denom: U256) -> RationalU256 {
if denom.is_zero() {
panic!("denominator == 0");
}
let mut ret = RationalU256::new_raw(numer, denom);
ret.reduce();
ret
}
#[inline]
pub const fn new_raw(numer: U256, denom: U256) -> RationalU256 {
RationalU256 { numer, denom }
}
#[inline]
pub const fn from_u256(t: U256) -> RationalU256 {
RationalU256::new_raw(t, U256::one())
}
#[inline]
pub fn is_zero(&self) -> bool {
self.numer.is_zero()
}
#[inline]
pub const fn zero() -> RationalU256 {
RationalU256::new_raw(U256::zero(), U256::one())
}
#[inline]
pub const fn one() -> RationalU256 {
RationalU256::new_raw(U256::one(), U256::one())
}
#[inline]
pub fn into_u256(self) -> U256 {
self.numer / self.denom
}
#[inline]
pub fn saturating_sub(self, rhs: RationalU256) -> Self {
if self.denom == rhs.denom {
let (numer, overflowing) = self.numer.overflowing_sub(&rhs.numer);
return if overflowing {
RationalU256::zero()
} else {
RationalU256::new(numer, self.denom)
};
}
let gcd = self.denom.gcd(&rhs.denom);
let lcm = &self.denom * (&rhs.denom / gcd);
let lhs_numer = &self.numer * (&lcm / self.denom);
let rhs_numer = &rhs.numer * (&lcm / &rhs.denom);
let (numer, overflowing) = lhs_numer.overflowing_sub(&rhs_numer);
if overflowing {
RationalU256::zero()
} else {
RationalU256::new(numer, lcm)
}
}
#[inline]
pub fn saturating_sub_u256(self, rhs: U256) -> Self {
let (numer, overflowing) = self.numer.overflowing_sub(&(&self.denom * rhs));
if overflowing {
RationalU256::zero()
} else {
RationalU256::new_raw(numer, self.denom)
}
}
fn reduce(&mut self) {
let g = self.numer.gcd(&self.denom);
self.numer = &self.numer / &g;
self.denom = &self.denom / &g;
}
}
impl Mul<&RationalU256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn mul(self, rhs: &RationalU256) -> RationalU256 {
let gcd_ad = self.numer.gcd(&rhs.denom);
let gcd_bc = self.denom.gcd(&rhs.numer);
RationalU256::new_raw(
(&self.numer / &gcd_ad) * (&rhs.numer / &gcd_bc),
(&self.denom / gcd_bc) * (&rhs.denom / gcd_ad),
)
}
}
impl Mul<RationalU256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn mul(self, rhs: RationalU256) -> RationalU256 {
self.mul(&rhs)
}
}
impl Mul<&RationalU256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn mul(self, rhs: &RationalU256) -> RationalU256 {
(&self).mul(rhs)
}
}
impl Mul<RationalU256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn mul(self, rhs: RationalU256) -> RationalU256 {
(&self).mul(&rhs)
}
}
impl Mul<&U256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn mul(self, rhs: &U256) -> RationalU256 {
let gcd = self.denom.gcd(rhs);
RationalU256::new_raw(&self.numer * (rhs.div(&gcd)), (&self.denom).div(gcd))
}
}
impl Mul<U256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn mul(self, rhs: U256) -> RationalU256 {
self.mul(&rhs)
}
}
impl Mul<U256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn mul(self, rhs: U256) -> RationalU256 {
(&self).mul(&rhs)
}
}
impl Mul<&U256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn mul(self, rhs: &U256) -> RationalU256 {
(&self).mul(rhs)
}
}
impl Div<&RationalU256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn div(self, rhs: &RationalU256) -> RationalU256 {
let gcd_ac = self.numer.gcd(&rhs.numer);
let gcd_bd = self.denom.gcd(&rhs.denom);
RationalU256::new_raw(
(&self.numer / &gcd_ac) * (&rhs.denom / &gcd_bd),
(&self.denom / gcd_bd) * (&rhs.numer / gcd_ac),
)
}
}
impl Div<RationalU256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn div(self, rhs: RationalU256) -> RationalU256 {
(&self).div(&rhs)
}
}
impl Div<RationalU256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn div(self, rhs: RationalU256) -> RationalU256 {
self.div(&rhs)
}
}
impl Div<&RationalU256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn div(self, rhs: &RationalU256) -> RationalU256 {
(&self).div(rhs)
}
}
impl Div<&U256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn div(self, rhs: &U256) -> RationalU256 {
let gcd = self.numer.gcd(rhs);
RationalU256::new_raw(&self.numer / &gcd, &self.denom * (rhs / gcd))
}
}
impl Div<U256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn div(self, rhs: U256) -> RationalU256 {
(&self).div(&rhs)
}
}
impl Div<&U256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn div(self, rhs: &U256) -> RationalU256 {
(&self).div(rhs)
}
}
impl Div<U256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn div(self, rhs: U256) -> RationalU256 {
(self).div(&rhs)
}
}
impl Add<&RationalU256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn add(self, rhs: &RationalU256) -> RationalU256 {
if self.denom == rhs.denom {
RationalU256::new(&self.numer + &rhs.numer, self.denom.clone())
} else {
let gcd = self.denom.gcd(&rhs.denom);
let lcm = &self.denom * (&rhs.denom / gcd);
let lhs_numer = &self.numer * (&lcm / &self.denom);
let rhs_numer = &rhs.numer * (&lcm / &rhs.denom);
RationalU256::new(lhs_numer + rhs_numer, lcm)
}
}
}
impl Add<RationalU256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn add(self, rhs: RationalU256) -> RationalU256 {
(&self).add(&rhs)
}
}
impl Add<&RationalU256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn add(self, rhs: &RationalU256) -> RationalU256 {
(&self).add(rhs)
}
}
impl Add<RationalU256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn add(self, rhs: RationalU256) -> RationalU256 {
(self).add(&rhs)
}
}
impl Add<&U256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn add(self, rhs: &U256) -> RationalU256 {
RationalU256::new_raw(&self.numer + (&self.denom * rhs), self.denom.clone())
}
}
impl Add<U256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn add(self, rhs: U256) -> RationalU256 {
(&self).add(&rhs)
}
}
impl Add<&U256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn add(self, rhs: &U256) -> RationalU256 {
(&self).add(rhs)
}
}
impl Add<U256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn add(self, rhs: U256) -> RationalU256 {
self.add(&rhs)
}
}
impl Sub<&RationalU256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn sub(self, rhs: &RationalU256) -> RationalU256 {
if self.denom == rhs.denom {
RationalU256::new(&self.numer - &rhs.numer, self.denom.clone())
} else {
let gcd = self.denom.gcd(&rhs.denom);
let lcm = &self.denom * (&rhs.denom / gcd);
let lhs_numer = &self.numer * (&lcm / &self.denom);
let rhs_numer = &rhs.numer * (&lcm / &rhs.denom);
RationalU256::new(lhs_numer - rhs_numer, lcm)
}
}
}
impl Sub<RationalU256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn sub(self, rhs: RationalU256) -> RationalU256 {
(&self).sub(&rhs)
}
}
impl Sub<&RationalU256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn sub(self, rhs: &RationalU256) -> RationalU256 {
(&self).sub(rhs)
}
}
impl Sub<RationalU256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn sub(self, rhs: RationalU256) -> RationalU256 {
self.sub(&rhs)
}
}
impl Sub<&U256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn sub(self, rhs: &U256) -> RationalU256 {
RationalU256::new_raw(&self.numer - (&self.denom * rhs), self.denom.clone())
}
}
impl Sub<U256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn sub(self, rhs: U256) -> RationalU256 {
(&self).sub(&rhs)
}
}
impl Sub<&U256> for RationalU256 {
type Output = RationalU256;
#[inline]
fn sub(self, rhs: &U256) -> RationalU256 {
(&self).sub(rhs)
}
}
impl Sub<U256> for &RationalU256 {
type Output = RationalU256;
#[inline]
fn sub(self, rhs: U256) -> RationalU256 {
self.sub(&rhs)
}
}
impl PartialOrd for RationalU256 {
fn partial_cmp(&self, other: &RationalU256) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for RationalU256 {
fn cmp(&self, other: &RationalU256) -> Ordering {
let gcd = self.denom.gcd(&other.denom);
let lhs = &self.numer * (&other.denom / &gcd);
let rhs = &other.numer * (&self.denom / &gcd);
lhs.cmp(&rhs)
}
}