From a8de0cfa88249679a152f25fd2c54f9157424515 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Wed, 11 Mar 2020 10:52:49 -0400 Subject: [PATCH] Add borrowing for subtraction --- src/bigint.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/src/bigint.rs b/src/bigint.rs index 6f4a7f6..3e8b78b 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -1,6 +1,7 @@ #![allow(unused_variables)] //! \[WIP\] Arbitrarily large integers use crate::num::*; +use crate::num::Sign::*; use core::ops::{ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Sub, SubAssign, }; @@ -100,6 +101,10 @@ impl Add for BigInt { fn add(self, rhs: Self) -> Self::Output { // @TODO: handle signs + if self.sign == Positive && rhs.sign == Negative { + return self - -rhs; + } + let mut out = BigInt::new_empty(); let u_digits = self.inner.len(); @@ -153,16 +158,37 @@ impl Sub for BigInt { let a = *self.inner.get(i).unwrap_or(&0usize); let b = *rhs.inner.get(i).unwrap_or(&0usize); - if a > b { - out.inner.push(a - b - borrow); + if a == 0 && b == 0 { + continue; + } + + if a > 0 && (a - borrow) >= b { + let res = a - b - borrow; + + // Don't add an extra zero if you borrowed everything + // from the most significant digit + if res == 0 && digits > 0 && i == digits -1 { + return out; + } + + out.inner.push(res); borrow = 0; - } else if a < b { - todo!(); - } else { - todo!(); + } else { + // To prevent subtraction overflow, the max borrowed + // value is usize::MAX. The rest of the borrowed value + // will be added on afterwords. + // In base ten, this would be like: + // 18 - 9 = 9-9 + 9 + let rem = (a + 1) - borrow; + let res = (core::usize::MAX - b) + rem; + out.inner.push(res); + + borrow = 1; } } + out.trim_zeros(); + out } } @@ -368,9 +394,26 @@ mod tests { let diff = a - b; assert_eq!( - diff.inner[0], + diff.clone().inner[0], core::usize::MAX - core::u16::MAX as usize ); + assert_eq!(diff.inner.len(), 1); + } + + #[test] + fn test_sub_borrow() { + let a = BigInt { + inner: vec![0, 1], + sign: Positive + }; + + let b = BigInt::from(2); + let diff = a - b; + assert_eq!(diff.clone().inner.len(), 1, "{:#?}", diff.clone()); + assert_eq!( + diff.inner[0], + core::usize::MAX - 1 + ); } #[test]