From 8260e7fc92c0c91ceef0861231fd01d224d6258d Mon Sep 17 00:00:00 2001 From: gbrochar Date: Wed, 22 Nov 2023 19:33:45 +0100 Subject: [PATCH] feat(*): prep 42 --- src/lib.rs | 29 ++++++++--- src/main.rs | 4 +- src/maths.rs | 120 ++++++++++++++++++++++++++++++++++++++++---- src/maths/solver.rs | 36 +++---------- 4 files changed, 143 insertions(+), 46 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4cbfe35..1aaa5c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,14 +8,29 @@ pub mod parser; pub mod maths; -pub fn pretty(v: &Vec) { - v[0].print(); - for i in 1..v.len() { - print!(" + "); - v[i].print(); - print!("x^{i}"); +pub fn format(v: &Vec) -> String { + let mut format; + format = v[0].format(); + if v.len() > 1 { + if format == "" { + format = format!("{}x", v[1].format()); + } else { + format = format!("{format} + {}x", v[1].format()); + } } - println!(""); + for i in 2..v.len() { + let tmp = v[i].format(); + if tmp != "" { + if format == ""{ + format = format!("{tmp}x^{i}"); + } else { + format = format!("{format} + {}x^{i}", tmp); + } + } + } + format = format.split("+ -").collect::>().join("- "); + format = format.split("1x").collect::>().join("x"); + format.split("1i").collect::>().join("i") } pub fn parse(query: &str) -> Result> { diff --git a/src/main.rs b/src/main.rs index fa02d3b..ec6a940 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,8 +16,10 @@ fn main() { println!("Error during evaluation: {e}"); process::exit(1); }); - computorv1::pretty(&evaluated); if is_equation { + println!("{} = 0", computorv1::format(&evaluated)); computorv1::maths::solver::solve(evaluated); + } else { + println!("{}", computorv1::format(&evaluated)); } } diff --git a/src/maths.rs b/src/maths.rs index d8ade07..7fd1179 100644 --- a/src/maths.rs +++ b/src/maths.rs @@ -16,6 +16,33 @@ fn one() -> GaussianRational { GaussianRational::new(Rational::new(1, 1), Rational::new(0, 1)) } +fn get_prime_factors(mut n: i128) -> Vec { + if n == 0 { + return [0].to_vec(); + } + let mut prime_factors = vec![]; + let mut prime = 3; + while n != 1 && prime * prime < n + 8 { + if n % (prime - 1) == 0 { + prime_factors.push(prime - 1); + n /= prime - 1; + } else if n % (prime + 1) == 0 { + prime_factors.push(prime + 1); + n /= prime + 1; + } else { + if prime > 5 { + prime += 6; + } else { + prime += 1; + } + } + } + if n != 1 { + prime_factors.push(n); + } + prime_factors +} + //TODO slow ? check Stein's algorithm (binaryGCD) + tests fn gcd(a: i128, b: i128) -> i128 { if b == 0 { @@ -56,12 +83,40 @@ impl Rational { Rational::new(self.numerator, self.denominator * 10) } + fn format_fract(&self) -> String { + let mut copy = self.clone(); + let factors = get_prime_factors(self.denominator); + dbg!(&factors); + let mut two_count = 0; + let mut five_count = 0; + for factor in factors { + if factor == 2 { + two_count += 1; + } else if factor == 5 { + five_count += 1; + } else { + return format!("{}/{}", self.numerator, self.denominator); + } + } + while two_count < five_count { + copy.numerator *= 2; + copy.denominator *= 2; + two_count += 1; + } + while five_count < two_count { + copy.numerator *= 5; + copy.denominator *= 5; + five_count += 1; + } + format!("{}.{}", copy.numerator / copy.denominator, copy.numerator % copy.denominator) + } + // TODO return string - pub fn print(&self) { + pub fn format(&self) -> String { match (self.numerator, self.denominator) { - (_, 1) => print!("{}", self.numerator), - _ => print!("{}/{}", self.numerator, self.denominator), - }; + (_, 1) => format!("{}", self.numerator), + _ => format!("{}", self.format_fract()), + } } // TODO rename or move to better scope, only used in complex div ? @@ -199,11 +254,13 @@ impl GaussianRational { } // TODO return string, avoid printing real or imag part if zero - pub fn print(&self) { - self.real.print(); - print!("+"); - self.imaginary.print(); - print!("i"); + pub fn format(&self) -> String { + match (self.real().is_zero(), self.imaginary.is_zero()) { + (true, true) => format!(""), + (true, false) => format!("{}i", self.imaginary.format()), + (false, true) => format!("{}", self.real.format()), + (false, false) => format!("{} + {}i", self.real.format(), self.imaginary.format()) + } } pub fn is_real(&self) -> bool { @@ -272,6 +329,24 @@ impl ops::Div for GaussianRational { mod tests { use super::*; + #[test] + fn constant_generators() { + assert_eq!(zero(), GaussianRational::new(Rational::new(0, 1), Rational::new(0, 1))); + assert_eq!(minus_one(), GaussianRational::new(Rational::new(-1, 1), Rational::new(0, 1))); + assert_eq!(one(), GaussianRational::new(Rational::new(1, 1), Rational::new(0, 1))); + } + + #[test] + fn get_prime_factors_test() { + assert_eq!(get_prime_factors(5), vec![5]); + assert_eq!(get_prime_factors(8), vec![2, 2, 2]); + assert_eq!(get_prime_factors(4), vec![2, 2]); + assert_eq!(get_prime_factors(9), vec![3, 3]); + assert_eq!(get_prime_factors(10), vec![2, 5]); + assert_eq!(get_prime_factors(18), vec![2, 3, 3]); + assert_eq!(get_prime_factors(16), vec![2, 2, 2, 2]); + } + #[test] fn gcd_test() { assert_eq!(gcd(7, 3), 1); @@ -343,6 +418,18 @@ mod tests { assert_eq!(rational.is_zero(), false); } + #[test] + fn format() { + let whole = Rational::new(5, 1); + let rational = Rational::new(5, 3); + let floating = Rational::new(5, 4); + assert_eq!(whole.format(), String::from("5")); + assert_eq!(rational.format(), String::from("5/3")); + assert_eq!(floating.format(), String::from("1.25")); + let floating = Rational::new(37, 25); + assert_eq!(floating.format(), String::from("1.48")); + } + #[test] fn getters() { let rational = Rational::new(5, 7); @@ -399,6 +486,21 @@ mod tests { assert_eq!(gaussian_rational.is_real(), true); } + #[test] + fn format() { + let whole = Rational::new(5, 1); + let rational = Rational::new(5, 3); + let zero = Rational::new(0, 1); + let a = GaussianRational::new(zero, zero); + let b = GaussianRational::new(zero, rational); + let c = GaussianRational::new(whole, zero); + let d = GaussianRational::new(whole, rational); + assert_eq!(a.format(), String::from("")); + assert_eq!(b.format(), String::from("5/3i")); + assert_eq!(c.format(), String::from("5")); + assert_eq!(d.format(), String::from("5 + 5/3i")); + } + #[test] fn getters() { let gaussian_rational = GaussianRational::new(Rational::new(5, 7), Rational::new(8, 3)); diff --git a/src/maths/solver.rs b/src/maths/solver.rs index 3dda2c5..75dd66a 100644 --- a/src/maths/solver.rs +++ b/src/maths/solver.rs @@ -13,7 +13,11 @@ fn degree_one(equation: Vec) { println!("Polynomial degree: 1"); let x = minus_one() * equation[0] / equation[1]; println!("The solution is"); - println!("{:?}", x); + let mut format = x.format(); + if format == "" { + format = String::from("0"); + } + println!("x = {}", format); } #[derive(Debug)] @@ -30,34 +34,13 @@ struct MyCompSqrt { sign: i128, } - -fn simplify_sqrt(mut n: i128) -> (i128, i128) { +fn simplify_sqrt(n: i128) -> (i128, i128) { if n == 0 { return (0, 0); } - let mut prime_factors = vec![]; - let mut prime = 3; - while n != 1 && prime * prime < n { - if n % (prime - 1) == 0 { - prime_factors.push(prime - 1); - n /= prime - 1; - } else if n % (prime + 1) == 0 { - prime_factors.push(prime + 1); - n /= prime + 1; - } else { - if prime > 5 { - prime += 6; - } else { - prime += 1; - } - } - } - if n != 1 { - prime_factors.push(n); - } + let mut prime_factors = get_prime_factors(n); let (mut natural, mut irrational) = (1, 1); prime_factors = prime_factors.into_iter().rev().collect(); - dbg!(&prime_factors); while prime_factors.len() > 1 { let pop = prime_factors.pop().unwrap(); if *prime_factors.last().unwrap() == pop { @@ -265,10 +248,7 @@ fn degree_two_complex(a: GaussianRational, b: GaussianRational, c: GaussianRatio fn sqrt(n: Rational, a: Rational) -> MySqrt { let numerator_irrational = n.numerator * n.denominator; - dbg!(numerator_irrational); let (mut numerator_natural, numerator_irrational) = simplify_sqrt(numerator_irrational); - dbg!(numerator_natural); - dbg!(numerator_irrational); numerator_natural *= a.denominator; let mut denominator = n.denominator * 2 * a.numerator; @@ -386,7 +366,6 @@ fn degree_two(equation: Vec) { } } - pub fn solve(mut equation: Vec) -> Vec { for i in (1..equation.len()).rev() { if equation[i] == zero() { @@ -395,7 +374,6 @@ pub fn solve(mut equation: Vec) -> Vec { break; } } - crate::pretty(&equation); match equation.len() { 0 => unreachable!(), 1 => degree_zero(equation),