PuzzleUtils/src/number/sub.rs

169 lines
4.6 KiB
Rust
Raw Normal View History

2024-11-25 10:39:52 +01:00
use std::{
cmp::min,
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();
if self_len != rhs_len {
let difference = (self_len).abs_diff(rhs_len);
let pad = vec![0isize; difference];
if min(self_len, rhs_len) == self_len {
self_digits = [self.digits, pad].concat();
2024-11-25 10:39:52 +01:00
} else {
rhs_digits = [rhs.digits, pad].concat();
2024-11-25 10:39:52 +01:00
}
}
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,
2024-11-25 10:39:52 +01:00
};
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()
}
(Sign::Positif, Sign::Negatif) => {
let comb = a + b + carry;
if comb > 9 {
carry = 1;
} else {
carry = 0;
}
comb % 10
}
(Sign::Negatif, Sign::Positif) => {
let comb = -a - b - carry;
if comb < -9 {
carry = 1;
} else {
carry = 0;
}
(comb % 10).abs()
}
(Sign::Negatif, Sign::Negatif) => {
let comb = -a + b + carry;
if comb > 10 {
carry = 1;
} else {
carry = 0;
}
if a > b {
sign = Sign::Negatif;
} else {
sign = Sign::Positif;
}
comb % 10
}
};
digits.push(comb);
}
if carry != 0 {
digits.push(carry);
}
Self { digits, sign }
2024-11-25 10:39:52 +01:00
}
}
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_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);
}
}