Skip to content

Commit

Permalink
Int cleanup (#733)
Browse files Browse the repository at this point in the history
  • Loading branch information
erik-3milabs authored Jan 10, 2025
1 parent f26fcc4 commit 9600cab
Show file tree
Hide file tree
Showing 10 changed files with 444 additions and 175 deletions.
2 changes: 1 addition & 1 deletion src/const_choice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ impl<const LIMBS: usize> ConstCtOption<Uint<LIMBS>> {
/// Returns the contained value, interpreting the underlying [`Uint`] value as an [`Int`].
#[inline]
pub const fn as_int(&self) -> ConstCtOption<Int<LIMBS>> {
ConstCtOption::new(Int::from_bits(self.value), self.is_some)
ConstCtOption::new(self.value.as_int(), self.is_some)
}
}

Expand Down
257 changes: 185 additions & 72 deletions src/int/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ impl<const LIMBS: usize> Int<LIMBS> {
ConstCtOption::new(value, overflow.not())
}

/// Perform `self + rhs`, returns the result, as well as a flag indicating whether the
/// addition overflowed.
/// Perform addition, raising the `overflow` flag on overflow.
pub const fn overflowing_add(&self, rhs: &Self) -> (Self, ConstChoice) {
// Step 1. add operands
let res = Self(self.0.wrapping_add(&rhs.0));
Expand All @@ -31,6 +30,7 @@ impl<const LIMBS: usize> Int<LIMBS> {
.eq(rhs.is_negative())
.and(self_msb.ne(res.is_negative()));

// Step 3. Construct result
(res, overflow)
}

Expand Down Expand Up @@ -106,107 +106,220 @@ impl<const LIMBS: usize> WrappingAdd for Int<LIMBS> {

#[cfg(test)]
mod tests {
use crate::{ConstChoice, I128, U128};

#[cfg(test)]
mod tests {
use crate::{I128, U128};
#[test]
fn checked_add() {
let min_plus_one = I128 {
0: I128::MIN.0.wrapping_add(&I128::ONE.0),
};
let max_minus_one = I128 {
0: I128::MAX.0.wrapping_sub(&I128::ONE.0),
};
let two = I128 {
0: U128::from(2u32),
};

#[test]
fn checked_add() {
let min_plus_one = I128 {
0: I128::MIN.0.wrapping_add(&I128::ONE.0),
};
let max_minus_one = I128 {
0: I128::MAX.0.wrapping_sub(&I128::ONE.0),
};
let two = I128 {
0: U128::from(2u32),
};
// lhs = MIN

// lhs = MIN
let result = I128::MIN.checked_add(&I128::MIN);
assert!(bool::from(result.is_none()));

let result = I128::MIN.checked_add(&I128::MIN);
assert!(bool::from(result.is_none()));
let result = I128::MIN.checked_add(&I128::MINUS_ONE);
assert!(bool::from(result.is_none()));

let result = I128::MIN.checked_add(&I128::MINUS_ONE);
assert!(bool::from(result.is_none()));
let result = I128::MIN.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::MIN);

let result = I128::MIN.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::MIN);
let result = I128::MIN.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), min_plus_one);

let result = I128::MIN.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), min_plus_one);
let result = I128::MIN.checked_add(&I128::MAX);
assert_eq!(result.unwrap(), I128::MINUS_ONE);

let result = I128::MIN.checked_add(&I128::MAX);
assert_eq!(result.unwrap(), I128::MINUS_ONE);
// lhs = -1

// lhs = -1
let result = I128::MINUS_ONE.checked_add(&I128::MIN);
assert!(bool::from(result.is_none()));

let result = I128::MINUS_ONE.checked_add(&I128::MIN);
assert!(bool::from(result.is_none()));
let result = I128::MINUS_ONE.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), two.checked_neg().unwrap());

let result = I128::MINUS_ONE.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), two.checked_neg().unwrap());
let result = I128::MINUS_ONE.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::MINUS_ONE);

let result = I128::MINUS_ONE.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::MINUS_ONE);
let result = I128::MINUS_ONE.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), I128::ZERO);

let result = I128::MINUS_ONE.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), I128::ZERO);
let result = I128::MINUS_ONE.checked_add(&I128::MAX);
assert_eq!(result.unwrap(), max_minus_one);

let result = I128::MINUS_ONE.checked_add(&I128::MAX);
assert_eq!(result.unwrap(), max_minus_one);
// lhs = 0

// lhs = 0
let result = I128::ZERO.checked_add(&I128::MIN);
assert_eq!(result.unwrap(), I128::MIN);

let result = I128::ZERO.checked_add(&I128::MIN);
assert_eq!(result.unwrap(), I128::MIN);
let result = I128::ZERO.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), I128::MINUS_ONE);

let result = I128::ZERO.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), I128::MINUS_ONE);
let result = I128::ZERO.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::ZERO);

let result = I128::ZERO.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::ZERO);
let result = I128::ZERO.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), I128::ONE);

let result = I128::ZERO.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), I128::ONE);
let result = I128::ZERO.checked_add(&I128::MAX);
assert_eq!(result.unwrap(), I128::MAX);

let result = I128::ZERO.checked_add(&I128::MAX);
assert_eq!(result.unwrap(), I128::MAX);
// lhs = 1

// lhs = 1
let result = I128::ONE.checked_add(&I128::MIN);
assert_eq!(result.unwrap(), min_plus_one);

let result = I128::ONE.checked_add(&I128::MIN);
assert_eq!(result.unwrap(), min_plus_one);
let result = I128::ONE.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), I128::ZERO);

let result = I128::ONE.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), I128::ZERO);
let result = I128::ONE.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::ONE);

let result = I128::ONE.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::ONE);
let result = I128::ONE.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), two);

let result = I128::ONE.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), two);
let result = I128::ONE.checked_add(&I128::MAX);
assert!(bool::from(result.is_none()));

let result = I128::ONE.checked_add(&I128::MAX);
assert!(bool::from(result.is_none()));
// lhs = MAX

// lhs = MAX
let result = I128::MAX.checked_add(&I128::MIN);
assert_eq!(result.unwrap(), I128::MINUS_ONE);

let result = I128::MAX.checked_add(&I128::MIN);
assert_eq!(result.unwrap(), I128::MINUS_ONE);
let result = I128::MAX.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), max_minus_one);

let result = I128::MAX.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), max_minus_one);
let result = I128::MAX.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::MAX);

let result = I128::MAX.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::MAX);
let result = I128::MAX.checked_add(&I128::ONE);
assert!(bool::from(result.is_none()));

let result = I128::MAX.checked_add(&I128::ONE);
assert!(bool::from(result.is_none()));
let result = I128::MAX.checked_add(&I128::MAX);
assert!(bool::from(result.is_none()));
}

#[test]
fn overflowing_add() {
let min_plus_one = I128 {
0: I128::MIN.0.wrapping_add(&I128::ONE.0),
};
let max_minus_one = I128 {
0: I128::MAX.0.wrapping_sub(&I128::ONE.0),
};
let two = I128 {
0: U128::from(2u32),
};

// lhs = MIN

let (_val, overflow) = I128::MIN.overflowing_add(&I128::MIN);
assert_eq!(overflow, ConstChoice::TRUE);

let (_val, overflow) = I128::MIN.overflowing_add(&I128::MINUS_ONE);
assert_eq!(overflow, ConstChoice::TRUE);

let (val, overflow) = I128::MIN.overflowing_add(&I128::ZERO);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MIN);

let (val, overflow) = I128::MIN.overflowing_add(&I128::ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, min_plus_one);

let (val, overflow) = I128::MIN.overflowing_add(&I128::MAX);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MINUS_ONE);

// lhs = -1

let (_val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::MIN);
assert_eq!(overflow, ConstChoice::TRUE);

let (val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::MINUS_ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, two.wrapping_neg());

let (val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::ZERO);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MINUS_ONE);

let (val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::ZERO);

let (val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::MAX);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, max_minus_one);

// lhs = 0

let (val, overflow) = I128::ZERO.overflowing_add(&I128::MIN);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MIN);

let (val, overflow) = I128::ZERO.overflowing_add(&I128::MINUS_ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MINUS_ONE);

let (val, overflow) = I128::ZERO.overflowing_add(&I128::ZERO);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::ZERO);

let (val, overflow) = I128::ZERO.overflowing_add(&I128::ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::ONE);

let (val, overflow) = I128::ZERO.overflowing_add(&I128::MAX);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MAX);

// lhs = 1

let (val, overflow) = I128::ONE.overflowing_add(&I128::MIN);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, min_plus_one);

let (val, overflow) = I128::ONE.overflowing_add(&I128::MINUS_ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::ZERO);

let (val, overflow) = I128::ONE.overflowing_add(&I128::ZERO);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::ONE);

let (val, overflow) = I128::ONE.overflowing_add(&I128::ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, two);

let (_val, overflow) = I128::ONE.overflowing_add(&I128::MAX);
assert_eq!(overflow, ConstChoice::TRUE);

// lhs = MAX

let (val, overflow) = I128::MAX.overflowing_add(&I128::MIN);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MINUS_ONE);

let (val, overflow) = I128::MAX.overflowing_add(&I128::MINUS_ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, max_minus_one);

let (val, overflow) = I128::MAX.overflowing_add(&I128::ZERO);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MAX);

let (_val, overflow) = I128::MAX.overflowing_add(&I128::ONE);
assert_eq!(overflow, ConstChoice::TRUE);

let result = I128::MAX.checked_add(&I128::MAX);
assert!(bool::from(result.is_none()));
}
let (_val, overflow) = I128::MAX.overflowing_add(&I128::MAX);
assert_eq!(overflow, ConstChoice::TRUE);
}
}
6 changes: 5 additions & 1 deletion src/int/bit_and.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,14 @@ mod tests {
#[test]
fn checked_and_ok() {
assert_eq!(I128::ZERO.checked_and(&I128::ONE).unwrap(), I128::ZERO);
assert_eq!(I128::ONE.checked_and(&I128::ONE).unwrap(), I128::ONE);
assert_eq!(I128::MAX.checked_and(&I128::ONE).unwrap(), I128::ONE);
}

#[test]
fn overlapping_and_ok() {
fn wrapping_and_ok() {
assert_eq!(I128::ZERO.wrapping_and(&I128::ONE), I128::ZERO);
assert_eq!(I128::ONE.wrapping_and(&I128::ONE), I128::ONE);
assert_eq!(I128::MAX.wrapping_and(&I128::ONE), I128::ONE);
}
}
6 changes: 5 additions & 1 deletion src/int/bit_or.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,14 @@ mod tests {
#[test]
fn checked_or_ok() {
assert_eq!(I128::ZERO.checked_or(&I128::ONE).unwrap(), I128::ONE);
assert_eq!(I128::ONE.checked_or(&I128::ONE).unwrap(), I128::ONE);
assert_eq!(I128::MAX.checked_or(&I128::ONE).unwrap(), I128::MAX);
}

#[test]
fn overlapping_or_ok() {
fn wrapping_or_ok() {
assert_eq!(I128::ZERO.wrapping_or(&I128::ONE), I128::ONE);
assert_eq!(I128::ONE.wrapping_or(&I128::ONE), I128::ONE);
assert_eq!(I128::MAX.wrapping_or(&I128::ONE), I128::MAX);
}
}
9 changes: 8 additions & 1 deletion src/int/bit_xor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,17 @@ mod tests {
#[test]
fn checked_xor_ok() {
assert_eq!(I128::ZERO.checked_xor(&I128::ONE).unwrap(), I128::ONE);
assert_eq!(I128::ONE.checked_xor(&I128::ONE).unwrap(), I128::ZERO);
assert_eq!(
I128::MAX.checked_xor(&I128::ONE).unwrap(),
I128::MAX - I128::ONE
);
}

#[test]
fn overlapping_xor_ok() {
fn wrapping_xor_ok() {
assert_eq!(I128::ZERO.wrapping_xor(&I128::ONE), I128::ONE);
assert_eq!(I128::ONE.wrapping_xor(&I128::ONE), I128::ZERO);
assert_eq!(I128::MAX.wrapping_xor(&I128::ONE), I128::MAX - I128::ONE);
}
}
Loading

0 comments on commit 9600cab

Please sign in to comment.