use std::{
cmp::Ordering,
fmt::Display,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
str::FromStr,
};
use crate::utility;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Fraction {
numerator: i32,
denominator: i32,
}
impl Fraction {
fn simplify(&mut self) {
if self.denominator < 0 {
self.numerator = -self.numerator;
self.denominator = -self.denominator;
}
let mut a = self.numerator.abs();
let mut b = self.denominator.abs();
while b > 0 {
let t = a % b;
a = b;
b = t;
}
self.numerator /= a;
self.denominator /= a;
}
pub fn new() -> Self {
Self { numerator: 0, denominator: 1 }
}
pub fn abs(&self) -> Self {
if self.numerator >= 0 {
*self
} else {
-*self
}
}
pub fn numerator(&self) -> i32 {
self.numerator
}
pub fn denominator(&self) -> i32 {
self.denominator
}
}
impl From<i32> for Fraction {
fn from(value: i32) -> Self {
Self {
numerator: value,
denominator: 1,
}
}
}
impl From<(i32, i32)> for Fraction {
fn from(value: (i32, i32)) -> Self {
utility::check_zero(value.1);
let mut f = Self {
numerator: value.0,
denominator: value.1,
};
f.simplify();
f
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct ParseFractionError;
impl FromStr for Fraction {
type Err = ParseFractionError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(numerator) = s.trim().parse() {
return Ok(Fraction { numerator, denominator: 1 });
}
let (numerator, denominator) = s.trim().split_once('/').ok_or(ParseFractionError)?;
let numerator = numerator.parse().map_err(|_| ParseFractionError)?;
let denominator = denominator.parse().map_err(|_| ParseFractionError)?;
Ok(Fraction::from((numerator, denominator)))
}
}
impl Default for Fraction {
fn default() -> Self {
Self::new()
}
}
impl PartialOrd for Fraction {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Fraction {
fn cmp(&self, other: &Self) -> Ordering {
match self.numerator * other.denominator - self.denominator * other.numerator {
..=-1 => Ordering::Less,
0 => Ordering::Equal,
1.. => Ordering::Greater,
}
}
}
impl Neg for Fraction {
type Output = Self;
fn neg(self) -> Self::Output {
Self {
numerator: -self.numerator,
denominator: self.denominator,
}
}
}
impl Add for Fraction {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::from((
self.numerator * rhs.denominator + self.denominator * rhs.numerator,
self.denominator * rhs.denominator,
))
}
}
impl Sub for Fraction {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self::from((
self.numerator * rhs.denominator - self.denominator * rhs.numerator,
self.denominator * rhs.denominator,
))
}
}
impl Mul for Fraction {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self::from((self.numerator * rhs.numerator, self.denominator * rhs.denominator))
}
}
impl Div for Fraction {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
Self::from((self.numerator * rhs.denominator, self.denominator * rhs.numerator))
}
}
impl Rem for Fraction {
type Output = Self;
fn rem(self, rhs: Self) -> Self::Output {
utility::check_zero(rhs.numerator);
Self::from((
(self.numerator * rhs.denominator) % (rhs.numerator * self.denominator),
self.denominator * rhs.denominator,
))
}
}
impl AddAssign for Fraction {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl SubAssign for Fraction {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl MulAssign for Fraction {
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl DivAssign for Fraction {
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs;
}
}
impl RemAssign for Fraction {
fn rem_assign(&mut self, rhs: Self) {
*self = *self % rhs;
}
}
impl Display for Fraction {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
if self.denominator == 1 {
write!(f, "{}", self.numerator)
} else {
write!(f, "{}/{}", self.numerator, self.denominator)
}
}
}
impl From<Fraction> for f64 {
fn from(value: Fraction) -> Self {
value.numerator as f64 / value.denominator as f64
}
}