use crate::{Choice, CtOption, Int, Uint, WrappingNeg};
impl<const LIMBS: usize> Int<LIMBS> {
#[must_use]
pub const fn overflowing_neg(&self) -> (Self, Choice) {
Self(self.0.bitxor(&Uint::MAX)).overflowing_add(&Int::ONE)
}
#[must_use]
pub const fn wrapping_neg(&self) -> Self {
self.overflowing_neg().0
}
#[must_use]
pub const fn wrapping_neg_if(&self, negate: Choice) -> Int<LIMBS> {
Self(self.0.wrapping_neg_if(negate))
}
#[must_use]
pub const fn checked_neg(&self) -> CtOption<Self> {
let (value, overflow) = self.overflowing_neg();
CtOption::new(value, overflow.not())
}
}
impl<const LIMBS: usize> WrappingNeg for Int<LIMBS> {
#[inline]
fn wrapping_neg(&self) -> Self {
self.wrapping_neg()
}
}
#[cfg(test)]
mod tests {
use crate::{Choice, I128};
#[test]
fn overflowing_neg() {
let min_plus_one = I128 {
0: I128::MIN.0.wrapping_add(&I128::ONE.0),
};
let (res, overflow) = I128::MIN.overflowing_neg();
assert_eq!(res, I128::MIN);
assert!(overflow.to_bool());
let (res, overflow) = I128::MINUS_ONE.overflowing_neg();
assert_eq!(res, I128::ONE);
assert!(!overflow.to_bool());
let (res, overflow) = I128::ZERO.overflowing_neg();
assert_eq!(res, I128::ZERO);
assert!(!overflow.to_bool());
let (res, overflow) = I128::ONE.overflowing_neg();
assert_eq!(res, I128::MINUS_ONE);
assert!(!overflow.to_bool());
let (res, overflow) = I128::MAX.overflowing_neg();
assert_eq!(res, min_plus_one);
assert!(!overflow.to_bool());
}
#[test]
fn wrapping_neg_if() {
let min_plus_one = I128 {
0: I128::MIN.0.wrapping_add(&I128::ONE.0),
};
let do_negate = Choice::TRUE;
assert_eq!(I128::MIN.wrapping_neg_if(do_negate), I128::MIN);
assert_eq!(I128::MINUS_ONE.wrapping_neg_if(do_negate), I128::ONE);
assert_eq!(I128::ZERO.wrapping_neg_if(do_negate), I128::ZERO);
assert_eq!(I128::ONE.wrapping_neg_if(do_negate), I128::MINUS_ONE);
assert_eq!(I128::MAX.wrapping_neg_if(do_negate), min_plus_one);
let do_not_negate = Choice::FALSE;
assert_eq!(I128::MIN.wrapping_neg_if(do_not_negate), I128::MIN);
assert_eq!(
I128::MINUS_ONE.wrapping_neg_if(do_not_negate),
I128::MINUS_ONE
);
assert_eq!(I128::ZERO.wrapping_neg_if(do_not_negate), I128::ZERO);
assert_eq!(I128::ONE.wrapping_neg_if(do_not_negate), I128::ONE);
assert_eq!(I128::MAX.wrapping_neg_if(do_not_negate), I128::MAX);
}
#[test]
fn checked_neg() {
assert!(I128::MIN.checked_neg().is_none().to_bool());
assert_eq!(I128::MINUS_ONE.checked_neg().unwrap(), I128::ONE);
assert_eq!(I128::ZERO.checked_neg().unwrap(), I128::ZERO);
assert_eq!(I128::ONE.checked_neg().unwrap(), I128::MINUS_ONE);
assert_eq!(
I128::MAX.checked_neg().unwrap(),
I128::from_be_hex("80000000000000000000000000000001")
);
let negative = I128::from_be_hex("91113333555577779999BBBBDDDDFFFF");
let positive = I128::from_be_hex("6EEECCCCAAAA88886666444422220001");
assert_eq!(negative.checked_neg().unwrap(), positive);
assert_eq!(positive.checked_neg().unwrap(), negative);
assert_eq!(
positive.checked_neg().unwrap().checked_neg().unwrap(),
positive
);
}
}