1use crate::{Choice, CtOption, Int, Uint, WrappingNeg};
4
5impl<const LIMBS: usize> Int<LIMBS> {
6 #[must_use]
13 pub const fn overflowing_neg(&self) -> (Self, Choice) {
14 Self(self.0.bitxor(&Uint::MAX)).overflowing_add(&Int::ONE)
15 }
16
17 #[must_use]
22 pub const fn wrapping_neg(&self) -> Self {
23 self.overflowing_neg().0
24 }
25
26 #[must_use]
31 pub const fn wrapping_neg_if(&self, negate: Choice) -> Int<LIMBS> {
32 Self(self.0.wrapping_neg_if(negate))
33 }
34
35 #[must_use]
40 pub const fn checked_neg(&self) -> CtOption<Self> {
41 let (value, overflow) = self.overflowing_neg();
42 CtOption::new(value, overflow.not())
43 }
44}
45
46impl<const LIMBS: usize> WrappingNeg for Int<LIMBS> {
47 #[inline]
48 fn wrapping_neg(&self) -> Self {
49 self.wrapping_neg()
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use crate::{Choice, I128};
56
57 #[test]
58 fn overflowing_neg() {
59 let min_plus_one = I128 {
60 0: I128::MIN.0.wrapping_add(&I128::ONE.0),
61 };
62
63 let (res, overflow) = I128::MIN.overflowing_neg();
64 assert_eq!(res, I128::MIN);
65 assert!(overflow.to_bool());
66
67 let (res, overflow) = I128::MINUS_ONE.overflowing_neg();
68 assert_eq!(res, I128::ONE);
69 assert!(!overflow.to_bool());
70
71 let (res, overflow) = I128::ZERO.overflowing_neg();
72 assert_eq!(res, I128::ZERO);
73 assert!(!overflow.to_bool());
74
75 let (res, overflow) = I128::ONE.overflowing_neg();
76 assert_eq!(res, I128::MINUS_ONE);
77 assert!(!overflow.to_bool());
78
79 let (res, overflow) = I128::MAX.overflowing_neg();
80 assert_eq!(res, min_plus_one);
81 assert!(!overflow.to_bool());
82 }
83
84 #[test]
85 fn wrapping_neg_if() {
86 let min_plus_one = I128 {
87 0: I128::MIN.0.wrapping_add(&I128::ONE.0),
88 };
89
90 let do_negate = Choice::TRUE;
91 assert_eq!(I128::MIN.wrapping_neg_if(do_negate), I128::MIN);
92 assert_eq!(I128::MINUS_ONE.wrapping_neg_if(do_negate), I128::ONE);
93 assert_eq!(I128::ZERO.wrapping_neg_if(do_negate), I128::ZERO);
94 assert_eq!(I128::ONE.wrapping_neg_if(do_negate), I128::MINUS_ONE);
95 assert_eq!(I128::MAX.wrapping_neg_if(do_negate), min_plus_one);
96
97 let do_not_negate = Choice::FALSE;
98 assert_eq!(I128::MIN.wrapping_neg_if(do_not_negate), I128::MIN);
99 assert_eq!(
100 I128::MINUS_ONE.wrapping_neg_if(do_not_negate),
101 I128::MINUS_ONE
102 );
103 assert_eq!(I128::ZERO.wrapping_neg_if(do_not_negate), I128::ZERO);
104 assert_eq!(I128::ONE.wrapping_neg_if(do_not_negate), I128::ONE);
105 assert_eq!(I128::MAX.wrapping_neg_if(do_not_negate), I128::MAX);
106 }
107
108 #[test]
109 fn checked_neg() {
110 assert!(I128::MIN.checked_neg().is_none().to_bool());
111 assert_eq!(I128::MINUS_ONE.checked_neg().unwrap(), I128::ONE);
112 assert_eq!(I128::ZERO.checked_neg().unwrap(), I128::ZERO);
113 assert_eq!(I128::ONE.checked_neg().unwrap(), I128::MINUS_ONE);
114 assert_eq!(
115 I128::MAX.checked_neg().unwrap(),
116 I128::from_be_hex("80000000000000000000000000000001")
117 );
118
119 let negative = I128::from_be_hex("91113333555577779999BBBBDDDDFFFF");
120 let positive = I128::from_be_hex("6EEECCCCAAAA88886666444422220001");
121 assert_eq!(negative.checked_neg().unwrap(), positive);
122 assert_eq!(positive.checked_neg().unwrap(), negative);
123 assert_eq!(
124 positive.checked_neg().unwrap().checked_neg().unwrap(),
125 positive
126 );
127 }
128}