diff --git a/src/fraction.rs b/src/fraction.rs new file mode 100644 index 0000000..97e0e85 --- /dev/null +++ b/src/fraction.rs @@ -0,0 +1,80 @@ +use std::{collections::HashSet, error::Error}; + +use crate::number::Number; + +#[derive(Debug, PartialEq, Eq)] +pub struct Fraction { + numerator: Number, + denominator: Number, +} + +pub struct Rational {} + +impl Fraction { + pub fn new(numerator: Number, denominator: Number) -> Result> { + if denominator == 0.into() { + return Err(Box::from("Division by 0")); + } + let mut f = Fraction { + numerator, + denominator, + }; + f.reduce(); + Ok(f) + } + + pub fn reduce(&mut self) { + let gcd = Number::gcd(self.numerator.clone(), self.denominator.clone()); + self.numerator = self.numerator.clone() / gcd.clone(); + self.denominator = self.denominator.clone() / gcd.clone(); + } + + pub fn get_repeating(&self) -> Number { + let mut memory = HashSet::new(); + let mut div_with = self.numerator.clone(); + let mut repetition = Vec::new(); + loop { + let (div, rem) = Number::div_with_rem(div_with.clone(), self.denominator.clone()); + if rem != 0.into() && memory.contains(&rem) { + repetition.push(div.digits[0]); + return Number { + digits: repetition, + sign: crate::number::Sign::Positif, + }; + } + memory.insert(rem.clone()); + if div.digits.is_empty() { + div_with = div_with * 10; + } else { + repetition.push(div.digits[0]); + div_with = rem * 10; + } + } + } +} + +#[cfg(test)] +mod test { + use crate::number::Number; + + use super::Fraction; + + #[test] + fn test_reduce() { + let f = Fraction::new(120.into(), 90.into()).unwrap(); + assert_eq!( + f, + Fraction { + numerator: 4.into(), + denominator: 3.into() + } + ); + } + + #[test] + fn test_repeating() { + let f = Fraction::new(1.into(), 7.into()).unwrap(); + let rep = f.get_repeating(); + assert_eq!(rep, Number::from("142857")); + } +} diff --git a/src/lib.rs b/src/lib.rs index 40ccb35..7e82089 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ pub mod combination; +pub mod fraction; pub mod grid; pub mod math; pub mod number; diff --git a/src/math.rs b/src/math.rs index 11c08c5..0005961 100644 --- a/src/math.rs +++ b/src/math.rs @@ -80,3 +80,14 @@ pub fn fib(n: u64) -> u64 { last_two.0 } + +pub fn gcd(mut a: u64, mut b: u64) -> u64 { + loop { + let t = b; + b = a % b; + a = t; + if b == 0 { + return a; + } + } +} diff --git a/src/number.rs b/src/number.rs index cf4ecfc..67b3d09 100644 --- a/src/number.rs +++ b/src/number.rs @@ -147,7 +147,7 @@ impl Number { last_two.0 } - fn div_with_rem(n1: Number, n2: Number) -> (Number, Number) { + pub fn div_with_rem(n1: Number, n2: Number) -> (Number, Number) { let n1_len = n1.digits.len(); let n2_len = n2.digits.len(); if n2_len > n1_len { @@ -196,6 +196,17 @@ impl Number { } (res, remainder) } + + pub fn gcd(mut a: Number, mut b: Number) -> Number { + loop { + let t = b.clone(); + b = a % b; + a = t; + if b == Number::from(0) { + return a; + } + } + } } impl From for isize { @@ -236,10 +247,11 @@ impl From<&str> for Number { } impl From for Number { - fn from(value: isize) -> Self { + fn from(mut value: isize) -> Self { let mut sign = Sign::Positif; if value < 0 { sign = Sign::Negatif; + value *= -1; } let num_len = if value > 0 { (value as f64 + 1.0).log10().ceil() as usize @@ -400,7 +412,7 @@ mod number_tests { assert_eq!( number, Number { - digits: vec![1234], + digits: vec![1, 2, 3, 4], sign: Sign::Negatif } );