use super::U320;
impl U320 {
#[inline]
pub const fn overflowing_sub(&self, other: &U320) -> (U320, bool) {
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 = ((other.0[1] as u128) << 64) | (other.0[0] as u128);
let b_hi = ((other.0[3] as u128) << 64) | (other.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, t1) = self.0[4].overflowing_sub(other.0[4]);
let (top, t2) = top.overflowing_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,
]),
t1 | t2,
)
}
}
#[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]);
let (result, underflow) = a.overflowing_sub(&b);
assert_eq!(result, U320::from_be_limbs([0, 0, 0, 0, 7]));
assert!(!underflow);
}
#[test]
fn self_cancellation() {
let a = U320::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0, 0x1111]);
let (result, underflow) = a.overflowing_sub(&a);
assert_eq!(result, U320::ZERO);
assert!(!underflow);
}
#[test]
fn borrow_propagation() {
let a = U320::from_be_limbs([1, 0, 0, 0, 0]);
let b = U320::ONE;
let (result, underflow) = a.overflowing_sub(&b);
assert_eq!(
result,
U320::from_be_limbs([0, u64::MAX, u64::MAX, u64::MAX, u64::MAX]),
);
assert!(!underflow);
}
#[test]
fn underflow_wraps() {
let (result, underflow) = U320::ZERO.overflowing_sub(&U320::ONE);
assert_eq!(result, U320::MAX);
assert!(underflow);
}
#[test]
fn cross_pair_borrow() {
let a = U320::from_be_limbs([0, 1, 0, 0, 0]);
let b = U320::ONE;
let (result, underflow) = a.overflowing_sub(&b);
assert_eq!(
result,
U320::from_be_limbs([0, 0, u64::MAX, u64::MAX, u64::MAX]),
);
assert!(!underflow);
}
#[test]
fn consistent_with_sub() {
let a = U320::from_be_limbs([5, 10, 15, 20, 25]);
let b = U320::from_be_limbs([1, 2, 3, 4, 5]);
let (result, _) = a.overflowing_sub(&b);
assert_eq!(result, a - b);
}
}