use super::U320;
use core::ops::Sub;
impl Sub for U320 {
type Output = U320;
#[inline]
fn sub(self, rhs: U320) -> U320 {
let a_lo = ((self.0[1] as u128) << 64) | (self.0[0] as u128);
let a_hi = ((self.0[3] as u128) << 64) | (self.0[2] as u128);
let b_lo = ((rhs.0[1] as u128) << 64) | (rhs.0[0] as u128);
let b_hi = ((rhs.0[3] as u128) << 64) | (rhs.0[2] as u128);
let (diff_lo, borrow1) = a_lo.overflowing_sub(b_lo);
let (diff_hi, u1) = a_hi.overflowing_sub(b_hi);
let (diff_hi, u2) = diff_hi.overflowing_sub(borrow1 as u128);
let top = self.0[4]
.wrapping_sub(rhs.0[4])
.wrapping_sub((u1 | u2) as u64);
U320([
diff_lo as u64,
(diff_lo >> 64) as u64,
diff_hi as u64,
(diff_hi >> 64) as u64,
top,
])
}
}
#[cfg(test)]
mod ai_tests {
use super::*;
#[test]
fn small_no_underflow() {
let a = U320::from_be_limbs([0, 0, 0, 0, 10]);
let b = U320::from_be_limbs([0, 0, 0, 0, 3]);
assert_eq!(a - b, U320::from_be_limbs([0, 0, 0, 0, 7]));
}
#[test]
fn self_cancellation() {
let a = U320::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0, 0x1111]);
assert_eq!(a - a, U320::from_be_limbs([0; 5]));
}
#[test]
fn borrow_propagation() {
let a = U320::from_be_limbs([1, 0, 0, 0, 0]);
let b = U320::from_be_limbs([0, 0, 0, 0, 1]);
assert_eq!(
a - b,
U320::from_be_limbs([0, u64::MAX, u64::MAX, u64::MAX, u64::MAX]),
);
}
#[test]
fn underflow_wraps() {
let a = U320::from_be_limbs([0; 5]);
let b = U320::from_be_limbs([0, 0, 0, 0, 1]);
assert_eq!(
a - b,
U320::from_be_limbs([u64::MAX, u64::MAX, u64::MAX, u64::MAX, u64::MAX]),
);
}
#[test]
fn cross_pair_borrow() {
let a = U320::from_be_limbs([0, 1, 0, 0, 0]);
let b = U320::from_be_limbs([0, 0, 0, 0, 1]);
assert_eq!(
a - b,
U320::from_be_limbs([0, 0, u64::MAX, u64::MAX, u64::MAX]),
);
}
#[test]
fn full_width_subtraction() {
let a = U320::from_be_limbs([u64::MAX, u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
let b = U320::from_be_limbs([0, u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
assert_eq!(a - b, U320::from_be_limbs([u64::MAX, 0, 0, 0, 0]));
}
}