#![allow(clippy::suspicious_op_assign_impl, clippy::suspicious_arithmetic_impl)]
use std::cmp;
use std::convert;
use std::fmt;
use std::ops;
pub static ZERO: Fraction = Fraction {
numerator: 0,
denominator: 1,
};
pub struct Fraction {
pub numerator: i64,
pub denominator: i64,
}
impl Fraction {
pub fn new(numerator: i64) -> Fraction {
Fraction {
numerator,
denominator: 1,
}
}
pub fn new_denom(mut numerator: i64, mut denominator: i64) -> Fraction {
if denominator == 0 {
panic!("Zero is an invalid denominator!");
}
if denominator < 0 {
numerator *= -1;
denominator *= -1;
}
let greatest_common_divisor = Fraction::greatest_common_divisor(numerator, denominator);
Fraction {
numerator: numerator / greatest_common_divisor,
denominator: denominator / greatest_common_divisor,
}
}
pub fn greatest_common_divisor(numerator: i64, denominator: i64) -> i64 {
let mut x = numerator;
let mut y = denominator;
while y != 0 {
let t = y;
y = x % y;
x = t;
}
x
}
pub fn reciprocal(self) -> Fraction {
Fraction::new_denom(self.denominator, self.numerator)
}
pub fn sqrt(&self) -> Fraction {
let mut decimal_mode = false;
let numerator = match self.numerator {
1 => 1,
4 => 2,
9 => 3,
16 => 4,
25 => 5,
36 => 6,
49 => 7,
64 => 8,
81 => 9,
100 => 10,
121 => 11,
144 => 12,
169 => 13,
196 => 14,
225 => 15,
256 => 16,
289 => 17,
324 => 18,
361 => 19,
400 => 20,
441 => 21,
484 => 22,
529 => 23,
576 => 24,
625 => 25,
676 => 26,
729 => 27,
784 => 28,
841 => 29,
900 => 30,
_ => {
decimal_mode = true;
self.numerator
}
};
let denominator = match self.denominator {
1 => 1,
4 => 2,
9 => 3,
16 => 4,
25 => 5,
36 => 6,
49 => 7,
64 => 8,
81 => 9,
100 => 10,
121 => 11,
144 => 12,
169 => 13,
196 => 14,
225 => 15,
256 => 16,
289 => 17,
324 => 18,
361 => 19,
400 => 20,
441 => 21,
484 => 22,
529 => 23,
576 => 24,
625 => 25,
676 => 26,
729 => 27,
784 => 28,
841 => 29,
900 => 30,
_ => {
decimal_mode = true;
self.denominator
}
};
if decimal_mode {
Fraction::from((numerator as f64 / denominator as f64).sqrt())
} else {
Fraction::new_denom(numerator, denominator)
}
}
pub fn cosine(self) -> Fraction {
let numerator = self.numerator as f64;
let denominator = self.denominator as f64;
Fraction::from((numerator / denominator).cos())
}
pub fn arc_cosine(self) -> Fraction {
let numerator = self.numerator as f64;
let denominator = self.denominator as f64;
Fraction::from((numerator / denominator).acos())
}
pub fn sine(self) -> Fraction {
let numerator = self.numerator as f64;
let denominator = self.denominator as f64;
Fraction::from((numerator / denominator).sin())
}
pub fn arc_sine(self) -> Fraction {
let numerator = self.numerator as f64;
let denominator = self.denominator as f64;
Fraction::from((numerator / denominator).asin())
}
pub fn tangent(self) -> Fraction {
let numerator = self.numerator as f64;
let denominator = self.denominator as f64;
Fraction::from((numerator / denominator).tan())
}
pub fn arc_tangent(self) -> Fraction {
let numerator = self.numerator as f64;
let denominator = self.denominator as f64;
Fraction::from((numerator / denominator).atan())
}
}
impl PartialEq for Fraction {
fn eq(&self, other: &Fraction) -> bool {
self.numerator == other.numerator && self.denominator == other.denominator
}
}
impl Eq for Fraction {}
impl PartialOrd for Fraction {
fn partial_cmp(&self, other: &Fraction) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Fraction {
fn cmp(&self, other: &Fraction) -> cmp::Ordering {
if ((self.numerator <= other.numerator) && self.denominator > other.denominator)
|| (self.numerator < other.numerator && self.denominator == other.denominator)
{
return cmp::Ordering::Less;
} else if (self.denominator <= other.denominator) && self.numerator >= other.numerator {
return cmp::Ordering::Greater;
}
cmp::Ordering::Equal
}
}
impl fmt::Debug for Fraction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.numerator == self.denominator || self.numerator == 0 || self.denominator == 1 {
if self.numerator < 0 {
write!(f, "{}", self.numerator)
} else {
write!(f, "+{}", self.numerator)
}
} else if self.numerator < 0 {
write!(f, "-[{}/{}]", -self.numerator, self.denominator)
} else {
write!(f, "+[{}/{}]", self.numerator, self.denominator)
}
}
}
impl fmt::Display for Fraction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.numerator == self.denominator || self.numerator == 0 || self.denominator == 1 {
if self.numerator < 0 {
write!(f, "{}", self.numerator)
} else {
write!(f, "+{}", self.numerator)
}
} else if self.numerator < 0 {
write!(f, "-({}/{})", -self.numerator, self.denominator)
} else {
write!(f, "+({}/{})", self.numerator, self.denominator)
}
}
}
impl ops::Add for Fraction {
type Output = Fraction;
fn add(self, other: Fraction) -> Fraction {
if self.denominator == other.denominator {
Fraction::new_denom(self.numerator + other.numerator, self.denominator)
} else {
Fraction::new_denom(
self.numerator * other.denominator + other.numerator * self.denominator,
self.denominator * other.denominator,
)
}
}
}
impl ops::AddAssign for Fraction {
fn add_assign(&mut self, other: Fraction) {
let numerator = self.numerator * other.denominator + other.numerator * self.denominator;
let denominator = self.denominator * other.denominator;
let greatest_common_divisor = Fraction::greatest_common_divisor(numerator, denominator);
self.numerator = numerator / greatest_common_divisor;
self.denominator = denominator / greatest_common_divisor;
}
}
impl ops::Sub for Fraction {
type Output = Fraction;
fn sub(self, other: Fraction) -> Fraction {
if self.denominator == other.denominator {
Fraction::new_denom(self.numerator - other.numerator, self.denominator)
} else {
Fraction::new_denom(
self.numerator * other.denominator - other.numerator * self.denominator,
self.denominator * other.denominator,
)
}
}
}
impl ops::SubAssign for Fraction {
fn sub_assign(&mut self, other: Fraction) {
if self.denominator == other.denominator {
let numerator = self.numerator - other.numerator;
let greatest_common_divisor =
Fraction::greatest_common_divisor(numerator, self.denominator);
self.numerator = numerator / greatest_common_divisor;
self.denominator /= greatest_common_divisor;
} else {
let numerator = self.numerator * other.denominator - other.numerator * self.denominator;
let denominator = self.denominator * other.denominator;
let greatest_common_divisor = Fraction::greatest_common_divisor(numerator, denominator);
self.numerator = numerator / greatest_common_divisor;
self.denominator = denominator / greatest_common_divisor;
}
}
}
impl ops::Mul for Fraction {
type Output = Fraction;
fn mul(self, other: Fraction) -> Fraction {
Fraction::new_denom(
self.numerator * other.numerator,
self.denominator * other.denominator,
)
}
}
impl ops::MulAssign for Fraction {
fn mul_assign(&mut self, other: Fraction) {
let numerator = self.numerator * other.numerator;
let denominator = self.denominator * other.denominator;
let greatest_common_divisor = Fraction::greatest_common_divisor(numerator, denominator);
self.numerator = numerator / greatest_common_divisor;
self.denominator = denominator / greatest_common_divisor;
}
}
impl ops::Div for Fraction {
type Output = Fraction;
fn div(self, other: Fraction) -> Fraction {
Fraction::new_denom(
self.numerator * other.denominator,
self.denominator * other.numerator,
)
}
}
impl ops::DivAssign for Fraction {
fn div_assign(&mut self, other: Fraction) {
let numerator = self.numerator * other.denominator;
let denominator = self.denominator * other.numerator;
let greatest_common_divisor = Fraction::greatest_common_divisor(numerator, denominator);
self.numerator = numerator / greatest_common_divisor;
self.denominator = denominator / greatest_common_divisor;
}
}
impl ops::Neg for Fraction {
type Output = Fraction;
fn neg(self) -> Fraction {
Fraction::new_denom(-self.numerator, self.denominator)
}
}
impl convert::From<i16> for Fraction {
fn from(item: i16) -> Self {
Fraction::new(i64::from(item))
}
}
impl convert::From<i32> for Fraction {
fn from(item: i32) -> Self {
Fraction::new(i64::from(item))
}
}
impl convert::From<i64> for Fraction {
fn from(item: i64) -> Self {
Fraction::new(item)
}
}
impl convert::From<f64> for Fraction {
fn from(item: f64) -> Self {
let denominator = 100_000_f64;
let numerator = (item * denominator).round();
Fraction::new_denom(numerator as i64, denominator as i64)
}
}
impl Copy for Fraction {}
impl Clone for Fraction {
fn clone(&self) -> Fraction {
*self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_test() {
let fraction1 = Fraction {
numerator: 23,
denominator: 21,
};
let fraction2 = Fraction::new_denom(23, 21);
assert_eq!(fraction1, fraction2);
}
#[test]
fn addition_test() {
let fraction1 = Fraction::new_denom(5, 2);
let fraction2 = Fraction::new_denom(4, 3);
let result_fraction = Fraction::new_denom(23, 6);
assert_eq!(fraction1 + fraction2, result_fraction);
}
#[test]
fn subtraction_test() {
let fraction1 = Fraction::new_denom(5, 2);
let fraction2 = Fraction::new_denom(4, 3);
let result_fraction1 = Fraction::new_denom(7, 6);
let result_fraction2 = Fraction::new_denom(-7, 6);
assert_eq!(fraction1 - fraction2, result_fraction1);
assert_eq!(fraction2 - fraction1, result_fraction2);
}
#[test]
fn multiplication_test() {
let fraction1 = Fraction::new_denom(5, 2);
let fraction2 = Fraction::new_denom(4, 3);
let result_fraction = Fraction::new_denom(10, 3);
assert_eq!(fraction1 * fraction2, result_fraction);
}
#[test]
fn division_test() {
let fraction1 = Fraction::new_denom(5, 2);
let fraction2 = Fraction::new_denom(4, 3);
let result_fraction = Fraction::new_denom(15, 8);
assert_eq!(fraction1 / fraction2, result_fraction);
}
#[test]
fn greatest_common_divisor_test() {
let numerator = 50;
let denominator = 20;
let greatest_common_divisor = Fraction::greatest_common_divisor(numerator, denominator);
assert_eq!(10, greatest_common_divisor);
}
#[test]
fn negation_test() {
let fraction = -Fraction::new_denom(5, 2);
let result_fraction = Fraction::new_denom(-5, 2);
assert_eq!(fraction, result_fraction);
}
#[test]
fn cosine_test() {
let fraction1 = Fraction::new_denom(3, 1);
let fraction2 = Fraction::new_denom(5, 1);
let result = Fraction::new_denom(41267, 50000);
assert_eq!(result, (fraction1 / fraction2).cosine());
}
#[test]
fn arc_cosine_test() {
let fraction1 = Fraction::new_denom(3, 1);
let fraction2 = Fraction::new_denom(5, 1);
let result = Fraction::new_denom(9273, 10000);
assert_eq!(result, (fraction1 / fraction2).arc_cosine());
}
#[test]
fn sine_test() {
let fraction1 = Fraction::new_denom(3, 1);
let fraction2 = Fraction::new_denom(5, 1);
let result = Fraction::new_denom(3529, 6250);
assert_eq!(result, (fraction1 / fraction2).sine());
}
#[test]
fn arc_sine_test() {
let fraction1 = Fraction::new_denom(3, 1);
let fraction2 = Fraction::new_denom(5, 1);
let result = Fraction::new_denom(1287, 2000);
assert_eq!(result, (fraction1 / fraction2).arc_sine());
}
#[test]
fn tangent_test() {
let fraction1 = Fraction::new_denom(3, 1);
let fraction2 = Fraction::new_denom(5, 1);
let result = Fraction::new_denom(34207, 50000);
assert_eq!(result, (fraction1 / fraction2).tangent());
}
#[test]
fn arc_tangent_test() {
let fraction1 = Fraction::new_denom(3, 1);
let fraction2 = Fraction::new_denom(5, 1);
let result = Fraction::new_denom(27021, 50000);
assert_eq!(result, (fraction1 / fraction2).arc_tangent());
}
}