diff --git a/src/number.rs b/src/number.rs index d919e97..41a1df3 100644 --- a/src/number.rs +++ b/src/number.rs @@ -78,6 +78,13 @@ impl Number { last_two.0 } + + pub fn abs(self) -> Self { + Number { + digits: self.digits, + sign: Sign::Positif, + } + } } impl Display for Number { diff --git a/src/number/add.rs b/src/number/add.rs index 3cfe093..d5574d0 100644 --- a/src/number/add.rs +++ b/src/number/add.rs @@ -1,5 +1,5 @@ use std::{ - cmp::min, + cmp::{min, Ordering}, iter::zip, ops::{Add, AddAssign}, }; @@ -14,6 +14,7 @@ impl Add for Number { let rhs_len = rhs.digits.len(); let mut self_digits = self.digits.clone(); let mut rhs_digits = rhs.digits.clone(); + let ord = self.clone().abs().cmp(&rhs.clone().abs()); if self_len != rhs_len { let difference = (self_len).abs_diff(rhs_len); let pad = vec![0i8; difference]; @@ -26,14 +27,24 @@ impl Add for Number { let zipped = zip(self_digits.iter(), rhs_digits.iter()); let mut carry = 0; let mut digits = Vec::new(); - let mut sign = match (self.sign, rhs.sign) { - (Sign::Positif, Sign::Positif) => Sign::Positif, - (Sign::Negatif, Sign::Negatif) => Sign::Negatif, - (Sign::Positif, Sign::Negatif) | (Sign::Negatif, Sign::Positif) => Sign::Positif, + let sign = match (self.sign, rhs.sign, ord) { + (Sign::Positif, Sign::Positif, _) => Sign::Positif, + (Sign::Negatif, Sign::Negatif, _) => Sign::Negatif, + (Sign::Positif, Sign::Negatif, Ordering::Greater) => Sign::Positif, + (Sign::Positif, Sign::Negatif, Ordering::Less) => Sign::Negatif, + (Sign::Negatif, Sign::Positif, Ordering::Greater) => Sign::Negatif, + (Sign::Negatif, Sign::Positif, Ordering::Less) => Sign::Positif, + (Sign::Positif, Sign::Negatif, Ordering::Equal) + | (Sign::Negatif, Sign::Positif, Ordering::Equal) => Sign::Positif, }; for (a, b) in zipped { - let comb = match (self.sign, rhs.sign) { - (Sign::Positif, Sign::Positif) => { + let comb = match (self.sign, rhs.sign, ord) { + (Sign::Positif, Sign::Negatif, Ordering::Equal) + | (Sign::Negatif, Sign::Positif, Ordering::Equal) => { + digits.push(0); + break; + } + (Sign::Positif, Sign::Positif, _) | (Sign::Negatif, Sign::Negatif, _) => { let comb = a + b + carry; if comb > 9 { carry = 1; @@ -42,43 +53,32 @@ impl Add for Number { } comb % 10 } - (Sign::Positif, Sign::Negatif) => { - let comb = a - b - carry; - if comb > 0 && b > a { + (Sign::Positif, Sign::Negatif, Ordering::Greater) + | (Sign::Negatif, Sign::Positif, Ordering::Greater) => { + let comb = if b > &(a - carry) { + let comb = a + 10 - b - carry; carry = 1; + comb } else { + let comb = a - b - carry; carry = 0; - } - if b > a { - sign = Sign::Negatif; - } else { - sign = Sign::Positif; - } + comb + }; (comb % 10).abs() } - (Sign::Negatif, Sign::Positif) => { - let comb = -a + b - carry; - if comb > 0 && a > b { + (Sign::Positif, Sign::Negatif, Ordering::Less) + | (Sign::Negatif, Sign::Positif, Ordering::Less) => { + let comb = if a > &(b - carry) { + let comb = b + 10 - a - carry; carry = 1; + comb } else { + let comb = b - a - carry; carry = 0; - } - if a > b { - sign = Sign::Negatif; - } else { - sign = Sign::Positif; - } + comb + }; (comb % 10).abs() } - (Sign::Negatif, Sign::Negatif) => { - let comb = a + b + carry; - if comb > 9 { - carry = 1; - } else { - carry = 0; - } - comb % 10 - } }; digits.push(comb); } @@ -87,6 +87,13 @@ impl Add for Number { digits.push(carry); } + for &digit in digits.clone().iter().rev() { + if digit != 0 || digits.len() == 1 { + break; + } + digits.pop(); + } + Self { digits, sign } } } @@ -104,13 +111,21 @@ mod test_number_add { use crate::number::Number; #[test] - fn add_positif() { + fn add_positif_1() { let a = Number::from(1); let b = 1.into(); let res = Number::from(2); assert_eq!(res, a + b); } + #[test] + fn add_positif_2() { + let a = Number::from(9); + let b = 1.into(); + let res = Number::from(10); + assert_eq!(res, a + b); + } + #[test] fn add_large_positif() { let a = Number::from(9); @@ -152,21 +167,36 @@ mod test_number_add { } #[test] - fn add_larger_positif_to_negatif() { + fn add_larger_positif_to_negatif_1() { let a = Number::from(-1); let b = (11).into(); let res = Number::from(10); assert_eq!(res, a + b); } + #[test] + fn add_larger_positif_to_negatif_2() { + let a = Number::from(-2); + let b = (11).into(); + let res = Number::from(9); + assert_eq!(res, a + b); + } #[test] - fn add_larger_negatif_to_positif() { + fn add_larger_negatif_to_positif_1() { let a = Number::from(1); let b = (-11).into(); let res = Number::from(-10); assert_eq!(res, a + b); } + #[test] + fn add_larger_negatif_to_positif_2() { + let a = Number::from(2); + let b = (-11).into(); + let res = Number::from(-9); + assert_eq!(res, a + b); + } + #[test] fn add_positif_to_larger_negatif() { let a = Number::from(-99); diff --git a/src/number/mul.rs b/src/number/mul.rs index 65c8121..96027fe 100644 --- a/src/number/mul.rs +++ b/src/number/mul.rs @@ -123,6 +123,14 @@ mod test_number_mul { assert_eq!(res, a * b); } + #[test] + fn mul_999_x_999() { + let a = Number::from(999); + let b = Number::from(999); + let res = Number::from(998001); + assert_eq!(res, a * b); + } + #[test] fn mul_big_1() { let a = Number::from("123"); diff --git a/src/number/ord.rs b/src/number/ord.rs index c7fef3e..da6fe76 100644 --- a/src/number/ord.rs +++ b/src/number/ord.rs @@ -46,6 +46,8 @@ impl Ord for Number { #[cfg(test)] mod test_number_ord { + use std::cmp::Ordering; + use crate::number::Number; #[test] @@ -53,6 +55,7 @@ mod test_number_ord { let a = Number::from(1); let b = Number::from(1); assert_eq!(a, b); + assert_eq!(Ordering::Equal, a.cmp(&b)); } #[test] @@ -60,6 +63,7 @@ mod test_number_ord { let a = Number::from(-1); let b = Number::from(-1); assert_eq!(a, b); + assert_eq!(Ordering::Equal, a.cmp(&b)); } #[test] @@ -67,6 +71,7 @@ mod test_number_ord { let a = Number::from(1); let b = Number::from(-1); assert!(a > b); + assert_eq!(Ordering::Greater, a.cmp(&b)); } #[test] @@ -74,6 +79,7 @@ mod test_number_ord { let a = Number::from(-1); let b = Number::from(1); assert!(a < b); + assert_eq!(Ordering::Less, a.cmp(&b)); } #[test] @@ -81,6 +87,7 @@ mod test_number_ord { let a = Number::from(-1); let b = Number::from(-10); assert!(a > b); + assert_eq!(Ordering::Greater, a.cmp(&b)); } #[test] @@ -88,6 +95,7 @@ mod test_number_ord { let a = Number::from(1); let b = Number::from(10); assert!(a < b); + assert_eq!(Ordering::Less, a.cmp(&b)); } #[test] @@ -95,6 +103,7 @@ mod test_number_ord { let a = Number::from(-10); let b = Number::from(-1); assert!(a < b); + assert_eq!(Ordering::Less, a.cmp(&b)); } #[test] @@ -102,5 +111,6 @@ mod test_number_ord { let a = Number::from(10); let b = Number::from(1); assert!(a > b); + assert_eq!(Ordering::Greater, a.cmp(&b)); } } diff --git a/src/number/sub.rs b/src/number/sub.rs index f3dd189..e47fc26 100644 --- a/src/number/sub.rs +++ b/src/number/sub.rs @@ -1,5 +1,5 @@ use std::{ - cmp::min, + cmp::{min, Ordering}, iter::zip, ops::{Sub, SubAssign}, }; @@ -14,6 +14,7 @@ impl Sub for Number { let rhs_len = rhs.digits.len(); let mut self_digits = self.digits.clone(); let mut rhs_digits = rhs.digits.clone(); + let ord = self.clone().abs().cmp(&rhs.clone().abs()); if self_len != rhs_len { let difference = (self_len).abs_diff(rhs_len); let pad = vec![0i8; difference]; @@ -23,31 +24,28 @@ impl Sub for Number { rhs_digits = [rhs.digits, pad].concat(); } } + println!("{:?} - {:?}", self_digits, rhs_digits); let zipped = zip(self_digits.iter(), rhs_digits.iter()); let mut carry = 0; let mut digits = Vec::new(); - let mut sign = match (self.sign, rhs.sign) { - (Sign::Positif, Sign::Negatif) => Sign::Positif, - (Sign::Negatif, Sign::Positif) => Sign::Negatif, - (Sign::Positif, Sign::Positif) | (Sign::Negatif, Sign::Negatif) => Sign::Positif, + let sign = match (self.sign, rhs.sign, ord) { + (Sign::Positif, Sign::Negatif, _) => Sign::Positif, + (Sign::Negatif, Sign::Positif, _) => Sign::Negatif, + (Sign::Positif, Sign::Positif, Ordering::Greater) => Sign::Positif, + (Sign::Positif, Sign::Positif, Ordering::Less) => Sign::Negatif, + (Sign::Negatif, Sign::Negatif, Ordering::Greater) => Sign::Negatif, + (Sign::Negatif, Sign::Negatif, Ordering::Less) => Sign::Positif, + (Sign::Positif, Sign::Positif, Ordering::Equal) + | (Sign::Negatif, Sign::Negatif, Ordering::Equal) => Sign::Positif, }; for (a, b) in zipped { - let comb = match (self.sign, rhs.sign) { - (Sign::Positif, Sign::Positif) => { - let comb = a - b - carry; - if comb < 0 { - carry = 1; - } else { - carry = 0; - } - if b > a { - sign = Sign::Negatif; - } else { - sign = Sign::Positif; - } - (comb % 10).abs() + let comb = match (self.sign, rhs.sign, ord) { + (Sign::Positif, Sign::Positif, Ordering::Equal) + | (Sign::Negatif, Sign::Negatif, Ordering::Equal) => { + digits.push(0); + break; } - (Sign::Positif, Sign::Negatif) => { + (Sign::Positif, Sign::Negatif, _) | (Sign::Negatif, Sign::Positif, _) => { let comb = a + b + carry; if comb > 9 { carry = 1; @@ -56,36 +54,47 @@ impl Sub for Number { } comb % 10 } - (Sign::Negatif, Sign::Positif) => { - let comb = -a - b - carry; - if comb < -9 { + (Sign::Positif, Sign::Positif, Ordering::Greater) + | (Sign::Negatif, Sign::Negatif, Ordering::Greater) => { + let comb = if b > &(a - carry) { + let comb = a + 10 - b - carry; carry = 1; + comb } else { + let comb = a - b - carry; carry = 0; - } + comb + }; (comb % 10).abs() } - (Sign::Negatif, Sign::Negatif) => { - let comb = -a + b + carry; - if comb > 10 { + (Sign::Positif, Sign::Positif, Ordering::Less) + | (Sign::Negatif, Sign::Negatif, Ordering::Less) => { + let comb = if a > &(b - carry) { + let comb = b + 10 - a - carry; carry = 1; + comb } else { + let comb = b - a - carry; carry = 0; - } - if a > b { - sign = Sign::Negatif; - } else { - sign = Sign::Positif; - } - comb % 10 + comb + }; + (comb % 10).abs() } }; digits.push(comb); } + if carry != 0 { digits.push(carry); } + for &digit in digits.clone().iter().rev() { + if digit != 0 || digits.len() == 1 { + break; + } + digits.pop(); + } + Self { digits, sign } } } @@ -150,6 +159,38 @@ mod test_number_sub { assert_eq!(res, a - b); } + #[test] + fn sub_larger_positif_from_positif_1() { + let a = Number::from(1); + let b = (11).into(); + let res = Number::from(-10); + assert_eq!(res, a - b); + } + + #[test] + fn sub_larger_positif_from_positif_2() { + let a = Number::from(2); + let b = (11).into(); + let res = Number::from(-9); + assert_eq!(res, a - b); + } + + #[test] + fn sub_positif_from_larger_positif_1() { + let a = Number::from(11); + let b = (1).into(); + let res = Number::from(10); + assert_eq!(res, a - b); + } + + #[test] + fn sub_positif_from_larger_positif_2() { + let a = Number::from(11); + let b = (2).into(); + let res = Number::from(9); + assert_eq!(res, a - b); + } + #[test] fn sub_positif_from_larger_negatif() { let a = Number::from(-99);