diff --git a/src/lib.rs b/src/lib.rs index 3b5a836..17fec59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,16 +4,7 @@ use crate::parser::sanitizer::sanitize_tokens; use crate::parser::ast_builder::{build_ast, Node}; pub mod parser; - -struct _Rational { - numerator: i128, - denominator: i128, -} - -struct _GaussianRational { - real: _Rational, - imaginary: _Rational, -} +pub mod maths; pub fn parse(query: &str) -> Result> { let tokens = tokenize(query)?; @@ -109,8 +100,3 @@ pub fn solve(equation: Vec) { _ => unreachable!(), } } - -#[cfg(test)] -mod tests { - use super::*; -} diff --git a/src/maths.rs b/src/maths.rs new file mode 100644 index 0000000..9d34d34 --- /dev/null +++ b/src/maths.rs @@ -0,0 +1,101 @@ +use std::ops; + +//TODO slow ? check Stein's algorithm (binaryGCD) +fn gcd(a: i128, b: i128) -> i128 { + if b == 0 { + a + } else { + gcd(b, a % b) + } +} + +#[derive(Debug, PartialEq, Clone)] +pub struct Rational { + numerator: i128, + denominator: i128, +} + +impl Rational { + pub fn new(numerator: i128, denominator: i128) -> Self { + Self { + numerator, + denominator, + } + } + + pub fn reduce(&self) -> Self { + let gcd = gcd(self.numerator, self.denominator); + Rational::new(self.numerator / gcd, self.denominator / gcd) + } +} + +impl ops::Add for Rational { + type Output = Rational; + + fn add(self, rhs: Rational) -> Rational { + Rational::new(self.numerator * rhs.denominator + rhs.numerator * self.denominator, self.denominator * rhs.denominator).reduce() + } +} + +impl ops::Add for Rational { + type Output = Rational; + + fn add(self, rhs: i128) -> Rational { + Rational::new(self.numerator + rhs * self.denominator, self.denominator).reduce() + } +} + +impl ops::Add for i128 { + type Output = Rational; + + fn add(self, rhs: Rational) -> Rational { + Rational::new(self * rhs.denominator + rhs.numerator, rhs.denominator).reduce() + } +} + +impl ops::Sub for Rational { + type Output = Rational; + + fn sub(self, rhs: Rational) -> Rational { + Rational::new(self.numerator * rhs.denominator - rhs.numerator * self.denominator, self.denominator * rhs.denominator).reduce() + } +} + +impl ops::Mul for Rational { + type Output = Rational; + + fn mul(self, rhs: Rational) -> Rational { + Rational::new(self.numerator * rhs.numerator, self.denominator * rhs.denominator).reduce() + } +} + +impl ops::Mul for Rational { + type Output = Rational; + + fn mul(self, rhs: i128) -> Rational { + Rational::new(self.numerator * rhs, self.denominator).reduce() + } +} + +impl ops::Mul for i128 { + type Output = Rational; + + fn mul(self, rhs: Rational) -> Rational { + Rational::new(self * rhs.numerator, rhs.denominator).reduce() + } +} + +#[derive(Debug, PartialEq, Clone)] +pub struct GaussianRational { + real: Rational, + imaginary: Rational, +} + +impl GaussianRational { + pub fn new(real: Rational, imaginary: Rational) -> Self { + Self { + real, + imaginary, + } + } +} diff --git a/src/parser/ast_builder.rs b/src/parser/ast_builder.rs index 9bb8038..550b86f 100644 --- a/src/parser/ast_builder.rs +++ b/src/parser/ast_builder.rs @@ -1,17 +1,5 @@ use super::Token; - -#[derive(Debug, PartialEq, Clone)] -pub struct Rational { - numerator: i128, - denominator: i128, -} - -#[derive(Debug, PartialEq, Clone)] -pub struct GaussianRational { - real: Rational, - imaginary: Rational, -} - +use crate::maths::{GaussianRational, Rational}; #[derive(Debug, PartialEq, Clone)] pub enum Node { @@ -23,76 +11,37 @@ pub enum Node { } } -/* - pub struct Node { - _lhs: Option>, - _rhs: Option>, - } - */ - -fn zero() -> GaussianRational { - GaussianRational { - real: Rational { - numerator: 0, - denominator: 1, - }, - imaginary: Rational { - numerator: 0, - denominator: 1, - } - } +fn rational_zero() -> Rational { + Rational::new(0, 1) } -fn minus_one() -> GaussianRational { - GaussianRational { - real: Rational { - numerator: -1, - denominator: 1, - }, - imaginary: Rational { - numerator: 0, - denominator: 1, - } - } +fn rational_one() -> Rational { + Rational::new(1, 1) +} + +fn rational_minus_one() -> Rational { + Rational::new(-1, 1) +} + + +fn zero() -> GaussianRational { + GaussianRational::new(rational_zero(), rational_zero()) } fn one() -> GaussianRational { - GaussianRational { - real: Rational { - numerator: 1, - denominator: 1, - }, - imaginary: Rational { - numerator: 0, - denominator: 1, - } - } + GaussianRational::new(rational_one(), rational_zero()) +} + +fn minus_one() -> GaussianRational { + GaussianRational::new(rational_minus_one(), rational_zero()) } fn i() -> GaussianRational { - GaussianRational { - real: Rational { - numerator: 0, - denominator: 1, - }, - imaginary: Rational { - numerator: 1, - denominator: 1, - } - } + GaussianRational::new(rational_zero(), rational_one()) } fn minus_i() -> GaussianRational { - GaussianRational { - real: Rational { - numerator: 0, - denominator: 1, - }, - imaginary: Rational { - numerator: -1, - denominator: 1, - } - } + GaussianRational::new(rational_zero(), rational_minus_one()) } fn x() -> Vec { @@ -128,34 +77,25 @@ fn get_parentheses_map(tokens: &Vec) -> Vec { } fn parse_number(string: &String, sign: i128) -> GaussianRational { - let mut number = Rational { - numerator: 0, - denominator: 1, - }; + let mut number = rational_zero(); let mut is_floating = false; for c in string.chars() { match c { '.' => is_floating = true, '0'..='9' => { - number.numerator = 10 * number.numerator + String::from(c).parse::().unwrap(); + number = 10 * number + String::from(c).parse::().unwrap(); if is_floating == true { - number.denominator *= 10; + number = number * Rational::new(1, 10); } } _ => unreachable!(), } } - number.numerator *= sign; + number = number * sign; - GaussianRational { - real: number, - imaginary: Rational { - numerator: 0, - denominator: 1, - } - } + GaussianRational::new(number, rational_zero()) } fn check_parentheses(tokens: &Vec) -> bool { @@ -432,8 +372,7 @@ mod tests { #[test] fn two_plus_two() { - let mut two = one(); - two.real.numerator = 2; + let two = GaussianRational::new(Rational::new(2, 1), rational_zero()); let tokens = vec![two_token(), plus(), two_token()]; let results = Node::Internal {