use super::U384;
impl U384 {
#[inline]
pub const fn overflowing_sub(&self, other: &U384) -> (U384, bool) {
let a_lo = ((self.0[1] as u128) << 64) | (self.0[0] as u128);
let a_mid = ((self.0[3] as u128) << 64) | (self.0[2] as u128);
let a_hi = ((self.0[5] as u128) << 64) | (self.0[4] as u128);
let b_lo = ((other.0[1] as u128) << 64) | (other.0[0] as u128);
let b_mid = ((other.0[3] as u128) << 64) | (other.0[2] as u128);
let b_hi = ((other.0[5] as u128) << 64) | (other.0[4] as u128);
let (diff_lo, borrow0) = a_lo.overflowing_sub(b_lo);
let (diff_mid, u1) = a_mid.overflowing_sub(b_mid);
let (diff_mid, u2) = diff_mid.overflowing_sub(borrow0 as u128);
let borrow1 = u1 | u2;
let (diff_hi, u3) = a_hi.overflowing_sub(b_hi);
let (diff_hi, u4) = diff_hi.overflowing_sub(borrow1 as u128);
(
U384([
diff_lo as u64,
(diff_lo >> 64) as u64,
diff_mid as u64,
(diff_mid >> 64) as u64,
diff_hi as u64,
(diff_hi >> 64) as u64,
]),
u3 | u4,
)
}
}
#[cfg(test)]
mod ai_tests {
use super::*;
#[test]
fn small_no_underflow() {
let a = U384::from_be_limbs([0, 0, 0, 0, 0, 10]);
let b = U384::from_be_limbs([0, 0, 0, 0, 0, 3]);
let (result, underflow) = a.overflowing_sub(&b);
assert_eq!(result, U384::from_be_limbs([0, 0, 0, 0, 0, 7]));
assert!(!underflow);
}
#[test]
fn underflow_wraps() {
let (result, underflow) = U384::ZERO.overflowing_sub(&U384::ONE);
assert_eq!(result, U384::MAX);
assert!(underflow);
}
#[test]
fn borrow_propagation() {
let a = U384::from_be_limbs([1, 0, 0, 0, 0, 0]);
let b = U384::from_be_limbs([0, 0, 0, 0, 0, 1]);
let (result, underflow) = a.overflowing_sub(&b);
assert_eq!(
result,
U384::from_be_limbs([0, u64::MAX, u64::MAX, u64::MAX, u64::MAX, u64::MAX]),
);
assert!(!underflow);
}
#[test]
fn self_cancellation() {
let a = U384::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0, 0x1111, 0x2222]);
let (result, underflow) = a.overflowing_sub(&a);
assert_eq!(result, U384::ZERO);
assert!(!underflow);
}
#[test]
fn borrow_lo_to_mid() {
let a = U384::from_be_limbs([0, 0, 0, 1, 0, 0]);
let b = U384::from_be_limbs([0, 0, 0, 0, 0, 1]);
let (result, underflow) = a.overflowing_sub(&b);
assert_eq!(
result,
U384::from_be_limbs([0, 0, 0, 0, u64::MAX, u64::MAX]),
);
assert!(!underflow);
}
}