use crate::int::types::Int;
#[inline]
pub(crate) const fn neg_twos_complement<const N: usize>(a: Int<N>) -> Int<N> {
let mut out = [0u64; N];
if N == 0 {
return Int::<N>::from_limbs(out);
}
let limbs = a.as_limbs();
let (s0, c0) = (!limbs[0]).overflowing_add(1);
out[0] = s0;
if c0 {
let mut carry: u64 = 1;
let mut i = 1;
while i < N {
let (s, c) = (!limbs[i]).overflowing_add(carry);
out[i] = s;
carry = c as u64;
i += 1;
}
let _ = carry;
} else {
let mut i = 1;
while i < N {
out[i] = !limbs[i];
i += 1;
}
}
Int::<N>::from_limbs(out)
}
#[cfg(test)]
mod tests {
use super::neg_twos_complement;
use crate::int::types::Int;
#[test]
fn neg_zero_is_zero() {
let z = Int::<1>::from_i64(0);
assert_eq!(neg_twos_complement(z).as_i128(), 0);
}
#[test]
fn neg_one_single_limb() {
let a = Int::<1>::from_i64(1);
assert_eq!(neg_twos_complement(a).as_i128(), -1);
}
#[test]
fn neg_minus_one() {
let a = Int::<1>::from_i64(-1);
assert_eq!(neg_twos_complement(a).as_i128(), 1);
}
#[test]
fn neg_min_wraps_to_min() {
let m = Int::<1>::from_i64(i64::MIN);
assert_eq!(neg_twos_complement(m).as_i128(), i64::MIN as i128);
}
#[test]
fn neg_double_is_identity() {
let v = Int::<3>::from_i128(i128::MAX);
let once = neg_twos_complement(v);
let twice = neg_twos_complement(once);
assert_eq!(twice.as_i128(), i128::MAX);
}
#[test]
fn neg_carry_across_limb_boundary() {
let a = Int::<2>::from_u128(1_u128 << 64);
let got = neg_twos_complement(a);
assert_eq!(got.as_i128(), -(1_i128 << 64));
}
}