use std::{ cmp::{min, Ordering}, iter::zip, ops::{Sub, SubAssign}, }; use super::{Number, Sign}; impl Sub for Number { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { let self_len = self.digits.len(); 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]; if min(self_len, rhs_len) == self_len { self_digits = [self.digits, pad].concat(); } else { rhs_digits = [rhs.digits, pad].concat(); } } let zipped = zip(self_digits.iter(), rhs_digits.iter()); let mut carry = 0; let mut digits = Vec::new(); 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, ord) { (Sign::Positif, Sign::Positif, Ordering::Equal) | (Sign::Negatif, Sign::Negatif, Ordering::Equal) => { digits.push(0); break; } (Sign::Positif, Sign::Negatif, _) | (Sign::Negatif, Sign::Positif, _) => { let comb = a + b + carry; if comb > 9 { carry = 1; } else { carry = 0; } comb % 10 } (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::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; 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 } } } impl SubAssign for Number { fn sub_assign(&mut self, rhs: Self) { let new = self.clone() - rhs; self.digits = new.digits; self.sign = new.sign; } } #[cfg(test)] mod test_number_sub { use crate::number::Number; #[test] fn sub_positif() { let a = Number::from(1); let b = 1.into(); let res = Number::from(0); assert_eq!(res, a - b); } #[test] fn sub_negatif() { let a = Number::from(-1); let b = (-1).into(); let res = Number::from(0); assert_eq!(res, a - b); } #[test] fn sub_negatif_from_positif() { let a = Number::from(1); let b = (-1).into(); let res = Number::from(2); assert_eq!(res, a - b); } #[test] fn sub_positif_from_negatif() { let a = Number::from(-1); let b = (1).into(); let res = Number::from(-2); assert_eq!(res, a - b); } #[test] fn sub_larger_positif_from_negatif() { let a = Number::from(-1); let b = (11).into(); let res = Number::from(-12); assert_eq!(res, a - b); } #[test] fn sub_larger_negatif_from_positif() { let a = Number::from(1); let b = (-11).into(); let res = Number::from(12); 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); let b = (11).into(); let res = Number::from(-110); assert_eq!(res, a - b); } #[test] fn sub_negatif_from_larger_positif() { let a = Number::from(99); let b = (-11).into(); let res = Number::from(110); assert_eq!(res, a - b); } }