From 36362458c8a99d5bb48e2e614c1083059564e572 Mon Sep 17 00:00:00 2001 From: gbrochar Date: Thu, 23 Nov 2023 07:26:38 +0100 Subject: [PATCH] feat(*): Approximations + fix print --- src/lib.rs | 8 +++---- src/main.rs | 1 + src/maths.rs | 52 ++++++++++++++++++++++++++++++++++++--------- src/maths/solver.rs | 37 ++++++++++++++++++++++++++------ 4 files changed, 78 insertions(+), 20 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 090d6a6..53583dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,16 +10,16 @@ pub mod maths; pub fn format(v: &Vec) -> String { let mut format; - format = v[0].format(); + format = v[0].format(false); if v.len() > 1 { if format == "" { - format = format!("{}x", v[1].format()); + format = format!("{}x", v[1].format(true)); } else { - format = format!("{format} + {}x", v[1].format()); + format = format!("{format} + {}x", v[1].format(true)); } } for i in 2..v.len() { - let tmp = v[i].format(); + let tmp = v[i].format(true); if tmp != "" { if format == ""{ format = format!("{tmp}x^{i}"); diff --git a/src/main.rs b/src/main.rs index ec6a940..51ebd97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,7 @@ fn main() { println!("{} = 0", computorv1::format(&evaluated)); computorv1::maths::solver::solve(evaluated); } else { + println!("{} is equal to:", args[1]); println!("{}", computorv1::format(&evaluated)); } } diff --git a/src/maths.rs b/src/maths.rs index 9cfb8dc..ae17774 100644 --- a/src/maths.rs +++ b/src/maths.rs @@ -16,6 +16,34 @@ fn one() -> GaussianRational { GaussianRational::new(Rational::new(1, 1), Rational::new(0, 1)) } +fn approx_sqrt_f64(n: f64) -> f64 { + let n = n as f64; + let mut result = n + 1.; + let mut factor = 1.; + while factor > f64::EPSILON { + while result * result > n { + result /= 1. + factor; + } + result *= 1. + factor; + factor /= 2.; + } + result +} + +fn approx_sqrt(n: i128) -> f64 { + let n = n as f64; + let mut result = n; + let mut factor = 1.; + while factor > f64::EPSILON { + while result * result > n { + result /= 1. + factor; + } + result *= 1. + factor; + factor /= 2.; + } + result +} + fn get_prime_factors(mut n: i128) -> Vec { if n == 0 { return [0].to_vec(); @@ -106,6 +134,9 @@ impl Rational { copy.denominator *= 5; five_count += 1; } + if copy.numerator < 0 { + copy.numerator *= -1; + } format!("{}.{}", copy.numerator / copy.denominator, copy.numerator % copy.denominator) } @@ -249,12 +280,13 @@ impl GaussianRational { GaussianRational::new(self.real, -1 * self.imaginary) } - 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 format(&self, parenthesis: bool) -> String { + match (self.real().is_zero(), self.imaginary.is_zero(), parenthesis) { + (true, true, _) => format!(""), + (true, false, _) => format!("{}i", self.imaginary.format()), + (false, true, _) => format!("{}", self.real.format()), + (false, false, false) => format!("{} + {}i", self.real.format(), self.imaginary.format()), + (false, false, true) => format!("({} + {}i)", self.real.format(), self.imaginary.format()) } } @@ -489,10 +521,10 @@ mod tests { 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")); + assert_eq!(a.format(false), String::from("")); + assert_eq!(b.format(false), String::from("5/3i")); + assert_eq!(c.format(false), String::from("5")); + assert_eq!(d.format(false), String::from("5 + 5/3i")); } #[test] diff --git a/src/maths/solver.rs b/src/maths/solver.rs index bfb93de..8eec809 100644 --- a/src/maths/solver.rs +++ b/src/maths/solver.rs @@ -13,7 +13,7 @@ fn degree_one(equation: Vec) { println!("Polynomial degree: 1"); let x = minus_one() * equation[0] / equation[1]; println!("The solution is"); - let mut format = x.format(); + let mut format = x.format(false); if format == "" { format = String::from("0"); } @@ -56,6 +56,7 @@ fn simplify_sqrt(n: i128) -> (i128, i128) { (natural, irrational) } +// Eric Naslund for the math https://math.stackexchange.com/questions/44406/how-do-i-get-the-square-root-of-a-complex-number fn comp_sqrt(c: GaussianRational) -> MyCompSqrt { let real = c.real(); let imag = c.imaginary(); @@ -107,7 +108,7 @@ fn comp_sqrt(c: GaussianRational) -> MyCompSqrt { } } -fn get_strings(left_part: Rational, sqrt_delta: MySqrt) -> (String, String, String, String, String, String) { +fn get_strings(left_part: Rational, sqrt_delta: &MySqrt) -> (String, String, String, String, String, String) { let mut a = left_part.numerator; let mut b = sqrt_delta.numerator_natural; if b < 0 { @@ -191,12 +192,12 @@ fn degree_two_complex(a: GaussianRational, b: GaussianRational, c: GaussianRatio let b = b / GaussianRational::new(Rational::new(-2, 1), Rational::new(0, 1)); - let mut sign = '+'; + let mut sign = '±'; if sqrt_delta.sign < 0 { - sign = '-'; + sign = '∓'; } - let (s1, s2, s3, s4, s5, s6) = get_strings(sqrt_delta.rational, sqrt_delta.sqrt); + let (s1, s2, s3, s4, s5, s6) = get_strings(sqrt_delta.rational, &sqrt_delta.sqrt); let mut string1 = String::from(""); let mut string2 = String::from(""); let mut string3 = String::from(""); @@ -218,7 +219,7 @@ fn degree_two_complex(a: GaussianRational, b: GaussianRational, c: GaussianRatio } string1 = format!("{string1} /{s1}\\ "); - string2 = format!("{string2} + sqrt | {s2} | "); + string2 = format!("{string2} ± sqrt | {s2} | "); string3 = format!("{string3} \\{s3}/ "); if b.imaginary.numerator != 0 { @@ -241,9 +242,19 @@ fn degree_two_complex(a: GaussianRational, b: GaussianRational, c: GaussianRatio string2 = format!("{string2}{sign} sqrt | {s5} | i"); string3 = format!("{string3} \\{s6}/ "); + println!("The two solutions are:"); println!("{string1}"); println!("{string2}"); println!("{string3}"); + println!("Approximations:"); + let sqrt = sqrt_delta.sqrt.numerator_natural as f64 * approx_sqrt(sqrt_delta.sqrt.numerator_irrational); + let left = b.real.numerator as f64 / b.real.denominator as f64; + let left_sqrt = approx_sqrt_f64((sqrt_delta.rational.numerator as f64 + sqrt) / sqrt_delta.rational.denominator as f64); + + let right = b.imaginary.numerator as f64 / b.imaginary.denominator as f64; + let right_sqrt = sqrt_delta.sign as f64 * approx_sqrt_f64((-sqrt_delta.rational.numerator as f64 + sqrt) / sqrt_delta.rational.denominator as f64); + println!("{}", format!("{} + {}i", left + left_sqrt, right + right_sqrt).split("+ -").collect::>().join("- ")); + println!("{}", format!("{} + {}i", left - left_sqrt, right - right_sqrt).split("+ -").collect::>().join("- ")); } fn sqrt(n: Rational, a: Rational) -> MySqrt { @@ -320,6 +331,20 @@ fn print_degree_two_real(left_part: Rational, sqrt_delta: MySqrt, imaginary: boo println!("{}{string}", " ".repeat(4 + (len - string.chars().count()) / 2)); println!("x = {}", "-".repeat(len)); println!("{}{d}", " ".repeat(4 + (len - d.to_string().len()) / 2)); + let mut right = (sqrt_delta.numerator_natural as f64 * approx_sqrt(sqrt_delta.numerator_irrational)) / left_part.denominator as f64; + let left = left_part.numerator as f64 / left_part.denominator as f64; + if right < 0. { + right *= -1.; + } + println!("Approximations:"); + if imaginary == true { + println!("{} - {}i", left, right); + println!("{} + {}i", left, right); + } else { + println!("{}", left - right); + println!("{}", left + right); + + } } else if string.len() > 0 { println!("x = {string}"); } else {