From 7702b67f07136d41435bb7dee130834965da469f Mon Sep 17 00:00:00 2001 From: Solomon Ucko Date: Sun, 14 Aug 2022 15:08:28 -0400 Subject: [PATCH] impl BitAnd for BigUint, add lots of tests --- Cargo.toml | 4 + src/logic.rs | 130 +++++++++++++++++-- src/ops.rs | 4 +- src/tests.rs | 357 ++++++++++++++++++--------------------------------- 4 files changed, 250 insertions(+), 245 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 94a134f..10aa20f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,7 @@ num-bigint = { version = "0.4.3", optional = true } [dev-dependencies] num-bigint = { version = "0.4.3" } + + +[profile.test] +opt-level = 2 diff --git a/src/logic.rs b/src/logic.rs index 89ed6fd..891cd75 100644 --- a/src/logic.rs +++ b/src/logic.rs @@ -1,3 +1,4 @@ +use crate::ops::{add_two_slices, sub_two_slices}; use crate::smallint::{SmallIntType, SmallUintType}; use crate::{SmallInt, SmallUint}; use core::cmp::Ordering; @@ -97,13 +98,20 @@ macro_rules! logic_op { } -macro_rules! inline_heap_to_inline { - ($fun:ident, $typ:ident, $typ_inner:ident, $typ_inline:ident; $i:ident, $slice:ident) => { +macro_rules! heap_to_inline { + ($typ_inline:ident; $slice:ident) => { let mut j = 0; for i in 0..4 { j <<= 32; j |= $slice[3 - i] as $typ_inline; } + j + } +} + +macro_rules! inline_heap_to_inline { + ($fun:ident, $typ:ident, $typ_inner:ident, $typ_inline:ident; $i:ident, $slice:ident) => { + let j = { heap_to_inline! { $typ_inline; $slice } }; $typ($typ_inner::Inline($i.$fun(j))) } } @@ -128,7 +136,7 @@ macro_rules! inline_heap_to_heap { macro_rules! heap_heap_create_res_shortest { - ($fun:ident; $min:ident, $slice1:ident, $slice2:ident) => { + ($fun:ident; $slice1:ident, $slice2:ident, $min:ident) => { let mut res = Vec::with_capacity($min); for l in 0..$min { res.push($slice1[l].$fun($slice2[l])); @@ -152,10 +160,31 @@ macro_rules! heap_heap_create_res_longest { } +macro_rules! heap_heap_return_heap_inner { + ($typ:ident, $typ_inner:ident; $res:ident) => { + let mut slice = ManuallyDrop::new($res); + $typ($typ_inner::Heap((slice.as_mut_ptr(), slice.len().try_into().unwrap()))) + } +} + +macro_rules! heap_heap_return_heap_inner_neg { + ($typ:ident, $typ_inner:ident; $res:ident) => { + let mut slice = ManuallyDrop::new($res); + $typ($typ_inner::Heap((slice.as_mut_ptr(), -isize::try_from(slice.len()).unwrap()))) + } +} + macro_rules! heap_heap_return_heap { ($typ:ident, $typ_inner:ident; $res:ident) => { - let mut slice = ManuallyDrop::new($res.into_boxed_slice()); - $typ($typ_inner::Heap((slice.as_mut_ptr(), slice.len().try_into().unwrap()))) + let res = $res.into_boxed_slice(); + heap_heap_return_heap_inner! { $typ, $typ_inner; res } + } +} + +macro_rules! heap_heap_return_heap_neg { + ($typ:ident, $typ_inner:ident; $res:ident) => { + let res = $res.into_boxed_slice(); + heap_heap_return_heap_inner_neg! { $typ, $typ_inner; res } } } @@ -183,7 +212,7 @@ logic_op! { BitAnd, BitAndAssign, SmallUint, SmallUintType, bitand, bitand_assign; i, j, p, q, s, t, slice, slice1, slice2, min, res; { inline_heap_to_inline! { bitand, SmallUint, SmallUintType, u128; i, slice } }, - { heap_heap_create_res_shortest! { bitand; min, slice1, slice2 } }, + { heap_heap_create_res_shortest! { bitand; slice1, slice2, min } }, { heap_heap_return_any! { SmallUint, SmallUintType, u128; res } } } @@ -205,28 +234,101 @@ logic_op! { +fn bitor_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec { + let mut result = if slice1.len() > slice2.len() { + slice1.to_vec() + } else { + slice2.to_vec() + }; + for l in 0..std::cmp::min(slice1.len(), slice2.len()) { + result[l] = slice1[l] | slice2[l]; + } + result +} + +fn bitand_two_slices_mixed_sign(positive: &[u32], negative: &[u32]) -> Vec { + // a & (-b) = (a | (b - 1)) + 1 - b + // 0 is not negative, so we can ignore it + let sub1 = sub_two_slices(negative, &[1]); + let or = bitor_two_slices(positive, &sub1); + let add = add_two_slices(&or, &[1]); + let sub2 = sub_two_slices(&add, negative); + sub2 +} logic_op! { - BitXor, BitXorAssign, SmallInt, SmallIntType, bitxor, bitxor_assign; + BitAnd, BitAndAssign, SmallInt, SmallIntType, bitand, bitand_assign; i, j, p, q, s, t; { - todo!() + let slice = unsafe { core::slice::from_raw_parts(p, s.unsigned_abs()) }; + match (i.cmp(&0), s.cmp(&0)) { + (Ordering::Equal, _) => SmallInt(SmallIntType::Inline(0)), + (Ordering::Greater, Ordering::Greater) => { + let j = { heap_to_inline! { i128; slice } }; + SmallInt(SmallIntType::Inline(i & j)) + }, + (Ordering::Greater, Ordering::Less) => { + let j = { heap_to_inline! { i128; slice } }; + SmallInt(SmallIntType::Inline(i & -j)) + }, + (Ordering::Less, Ordering::Greater) => { + let mut res = >::from(slice); + let mut inline = i; + for idx in 0..4 { + res[idx] &= inline as u32; + inline >>= 32; + } + heap_heap_return_heap_inner! { SmallInt, SmallIntType; res } + }, + (Ordering::Less, Ordering::Less) => { + let mut res = >::from(slice); + let j = { heap_to_inline! { i128; slice } }; + let lo = (i & j.wrapping_neg()).wrapping_neg(); + let mut lo_remaining = lo; + for idx in 0..4 { + res[idx] = lo_remaining as u32; + lo_remaining >>= 32; + } + + if lo == 0 && j != 0 { + let res2 = add_two_slices(&res, &[0, 0, 0, 0, 1]); + heap_heap_return_heap_neg! { SmallInt, SmallIntType; res2 } + } else { + heap_heap_return_heap_inner_neg! { SmallInt, SmallIntType; res } + } + }, + (_, Ordering::Equal) => unreachable!("0 must be inline"), + } }, { let slice1 = unsafe { core::slice::from_raw_parts(p, s.unsigned_abs()) }; - let slice2 = unsafe { core::slice::from_raw_parts(q, t as usize) }; + let slice2 = unsafe { core::slice::from_raw_parts(q, t.unsigned_abs()) }; match (s.cmp(&0), t.cmp(&0)) { (Ordering::Greater, Ordering::Greater) => { let min = std::cmp::min(slice1.len(), slice2.len()); #[allow(unused_mut)] - let mut res = { heap_heap_create_res_longest! { bitxor; slice1, slice2, min } }; + let mut res = { heap_heap_create_res_shortest! { bitand; slice1, slice2, min } }; - heap_heap_return_any! { SmallInt, SmallIntType, i128; res } + heap_heap_return_heap! { SmallInt, SmallIntType; res } + }, + (Ordering::Greater, Ordering::Less) => { + let res = bitand_two_slices_mixed_sign(slice1, slice2); + heap_heap_return_heap! { SmallInt, SmallIntType; res } + }, + (Ordering::Less, Ordering::Greater) => { + let res = bitand_two_slices_mixed_sign(slice2, slice1); + heap_heap_return_heap! { SmallInt, SmallIntType; res } + }, + (Ordering::Less, Ordering::Less) => { + // (-a) & (-b) = -(((a-1) | (b-1)) + 1) + // 0 is not negative, so we can ignore it + let sub1 = sub_two_slices(slice1, &[1]); + let sub2 = sub_two_slices(slice2, &[1]); + let tmp = bitor_two_slices(&sub1, &sub2); + let res = add_two_slices(&tmp, &[1]); + heap_heap_return_heap_neg! { SmallInt, SmallIntType; res } }, - (Ordering::Greater, Ordering::Less) => todo!(), - (Ordering::Less, Ordering::Greater) => todo!(), - (Ordering::Less, Ordering::Less) => todo!(), (Ordering::Equal, _) | (_, Ordering::Equal) => unreachable!("0 must be inline"), } } diff --git a/src/ops.rs b/src/ops.rs index 0bee046..5895afa 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -66,7 +66,7 @@ macro_rules! basic_op { }; } -fn add_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec { +pub(crate) fn add_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec { let s = slice1.len(); let j = slice2.len(); @@ -225,7 +225,7 @@ impl AddAssign for SmallInt { } } -fn sub_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec { +pub(crate) fn sub_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec { let b = slice1.len(); let s = slice2.len(); diff --git a/src/tests.rs b/src/tests.rs index f7d3666..9fad651 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -2,6 +2,7 @@ use crate::SmallInt; use crate::SmallUint; +use core::fmt::Debug; #[cfg(feature = "num-bigint")] use num_bigint::{BigInt, BigUint, Sign}; @@ -32,309 +33,207 @@ conversion_tests!(i64, test_i64); conversion_tests!(u128, test_u128); conversion_tests!(i128, test_i128); +fn run_tests_u_inner(test: impl Fn(BigUint)) { + for i in 0u8..=7 { + test(BigUint::from(i)); + } + for shift_scale in 1..=16 { + for shift_offset in -2..=2 { + let shift: i16 = (shift_scale * 32) + shift_offset; + test(BigUint::from(1u8) << shift); + for offset in 1u8..=7 { + test((BigUint::from(1u8) << shift) + BigUint::from(offset)); + test((BigUint::from(1u8) << shift) - BigUint::from(offset)); + } + } + } + test(BigUint::new(vec![3, 9, 8, 3, 1])); + test(BigUint::new(vec![5, 4, 9, 3, 1, 81])); +} + +#[allow(dead_code)] +fn run_tests_u_1(small: impl Fn(SmallUint) -> T, big: impl Fn(&BigUint) -> T) { + run_tests_u_inner(|i| { + let small_result = small(SmallUint::from(&i)); + let big_result = big(&i); + assert_eq!( + small_result, + big_result, + "{:#x}", i + ); + }); +} + +fn run_tests_u_2( + small: impl Fn(SmallUint, SmallUint) -> T, + big: impl Fn(&BigUint, &BigUint) -> T +) { + run_tests_u_inner(|i| run_tests_u_inner(|k| { + let small_result = small(SmallUint::from(&i), SmallUint::from(&k)); + let big_result = big(&i, &k); + assert_eq!( + small_result, + big_result, + "{:#x} {:#x}", i, k + ); + })); +} + +fn run_tests_i_inner(test: impl Fn(BigInt)) { + run_tests_u_inner(|value| { + test(BigInt::from_biguint(Sign::Plus, value.clone())); + test(BigInt::from_biguint(Sign::Minus, value)); + }); +} + +fn run_tests_i_1(small: impl Fn(SmallInt) -> T, big: impl Fn(&BigInt) -> T) { + run_tests_i_inner(|i| { + let small_result = small(SmallInt::from(&i)); + let big_result = big(&i); + assert_eq!( + small_result, + big_result, + "{:#x}", i + ); + }); +} + +fn run_tests_i_2( + small: impl Fn(SmallInt, SmallInt) -> T, + big: impl Fn(&BigInt, &BigInt) -> T +) { + run_tests_i_inner(|i| run_tests_i_inner(|k| { + let small_result = small(SmallInt::from(&i), SmallInt::from(&k)); + let big_result = big(&i, &k); + assert_eq!( + small_result, + big_result, + "{:#x} {:#x}", i, k + ); + })); +} + #[test] #[cfg(feature = "num-bigint")] fn test_cmp_u() { - let i = SmallUint::from(30u32); - let k = SmallUint::from(50u32); - assert!(i < k); - - let i = SmallUint::from(u128::MAX); - let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); - assert!(i < k); - - let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1])); - let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); - assert!(i < k); + run_tests_u_2( + |i, k| i.partial_cmp(&k), + |i, k| i.partial_cmp(&k), + ); } #[test] #[cfg(feature = "num-bigint")] fn test_cmp_i() { - let i = SmallInt::from(30u32); - let k = SmallInt::from(50u32); - assert!(i < k); - - let i = SmallInt::from(u128::MAX); - let k = SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81])); - assert!(i < k); - - let i = SmallInt::from(&BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1])); - let k = SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81])); - assert!(i < k); - - let i = SmallInt::from(30u32); - let k = -SmallInt::from(50u32); - assert!(k < i); - - let i = SmallInt::from(u128::MAX); - let k = -SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81])); - assert!(k < i); - - let i = SmallInt::from(&BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1])); - let k = -SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81])); - assert!(k < i); + run_tests_i_2( + |i, k| i.partial_cmp(&k), + |i, k| i.partial_cmp(&k), + ); } #[test] #[cfg(feature = "num-bigint")] fn test_op_add_u() { - let i = SmallUint::from(u128::MAX); - let k = SmallUint::from(u128::MAX); - let q = i + k; - assert_eq!(BigUint::from(&q), BigUint::from(u128::MAX) + u128::MAX); - - let i = SmallUint::from(u128::MAX); - let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); - let q = i + k; - assert_eq!( - BigUint::from(&q), - BigUint::new(vec![5, 4, 9, 3, 1, 81]) + u128::MAX - ); - - let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1])); - let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); - let q = i + k; - assert_eq!( - BigUint::from(&q), - BigUint::new(vec![3, 9, 8, 3, 1]) + BigUint::new(vec![5, 4, 9, 3, 1, 81]) + run_tests_u_2( + |i, k| BigUint::from(&(i + k)), + |i, k| i + k, ); } #[test] #[cfg(feature = "num-bigint")] fn test_op_add_i() { - let i = SmallInt::from(u128::MAX); - let k = -SmallInt::from(u128::MAX); - let q = i + k; - assert_eq!(BigInt::from(&q), BigInt::from(0)); - - let i = SmallInt::from(u128::MAX); - let k = -SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81])); - let q = i + k; - assert_eq!( - BigInt::from(&q), - u128::MAX - BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]) - ); - - let i = -SmallInt::from(&BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1])); - let k = SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81])); - let q = i + k; - assert_eq!( - BigInt::from(&q), - BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]) - - BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1]) + run_tests_i_2( + |i, k| BigInt::from(&(i + k)), + |i, k| i + k, ); } #[test] #[cfg(feature = "num-bigint")] fn test_op_mul_u() { - let i = SmallUint::from(u128::MAX); - let k = SmallUint::from(u128::MAX); - let q = i * k; - assert_eq!(BigUint::from(&q), BigUint::from(u128::MAX) * u128::MAX); - - let i = SmallUint::from(u32::MAX); - let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); - let q = i * k; - assert_eq!( - BigUint::from(&q), - BigUint::new(vec![5, 4, 9, 3, 1, 81]) * u32::MAX - ); - - let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1])); - let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); - let q = i * k; - assert_eq!( - BigUint::from(&q), - BigUint::new(vec![3, 9, 8, 3, 1]) * BigUint::new(vec![5, 4, 9, 3, 1, 81]) + run_tests_u_2( + |i, k| BigUint::from(&(i * k)), + |i, k| i * k, ); } #[test] #[cfg(feature = "num-bigint")] fn test_op_mul_i() { - let i = -SmallInt::from(u128::MAX); - let k = SmallInt::from(u128::MAX); - let q = i * k; - assert_eq!(BigInt::from(&q), -BigInt::from(u128::MAX) * u128::MAX); - - let i = -SmallInt::from(u32::MAX); - let k = -SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81])); - let q = i * k; - assert_eq!( - BigInt::from(&q), - BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]) * u32::MAX - ); - - let i = -SmallInt::from(&BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1])); - let k = SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81])); - let q = i * k; - assert_eq!( - BigInt::from(&q), - BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1]) - * -BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]) + run_tests_i_2( + |i, k| BigInt::from(&(i * k)), + |i, k| i * k, ); } #[test] #[cfg(feature = "num-bigint")] fn test_op_sub_u() { - let i = SmallUint::from(u128::MAX); - let k = SmallUint::from(u128::MAX); - let q = i - k; - assert_eq!(BigUint::from(&q), BigUint::from(u128::MAX) - u128::MAX); - - let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); - let i = SmallUint::from(u128::MAX); - let q = k - i; - assert_eq!( - BigUint::from(&q), - BigUint::new(vec![5, 4, 9, 3, 1, 81]) - u128::MAX - ); - - let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); - let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1])); - let q = k - i; - assert_eq!( - BigUint::from(&q), - BigUint::new(vec![5, 4, 9, 3, 1, 81]) - BigUint::new(vec![3, 9, 8, 3, 1]) + run_tests_u_2( + |i, k| (i >= k).then(|| BigUint::from(&(i - k))), + |i, k| (i >= k).then(|| i - k), ); } #[test] #[cfg(feature = "num-bigint")] fn test_op_sub_i() { - let i = -SmallInt::from(u128::MAX); - let k = SmallInt::from(u128::MAX); - let q = i - k; - assert_eq!(BigInt::from(&q), -BigInt::from(u128::MAX) - u128::MAX); - - let k = SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81])); - let i = -SmallInt::from(u128::MAX); - let q = k - i; - assert_eq!( - BigInt::from(&q), - BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]) + u128::MAX - ); - - let k = -SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81])); - let i = SmallInt::from(&BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1])); - let q = k - i; - assert_eq!( - BigInt::from(&q), - -(BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]) - + BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1])) + run_tests_i_2( + |i, k| BigInt::from(&(i - k)), + |i, k| i - k, ); } #[test] #[cfg(feature = "num-bigint")] fn test_op_and_u() { - let i = SmallUint::from(u128::MAX); - let k = SmallUint::from(u128::MAX); - let q = i & k; - assert_eq!( - BigUint::from(&q), - BigUint::from(u128::MAX) & BigUint::from(u128::MAX) + run_tests_u_2( + |i, k| BigUint::from(&(i & k)), + |i, k| i & k, ); +} - let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); - let i = SmallUint::from(u128::MAX); - let q = k & i; - assert_eq!( - BigUint::from(&q), - BigUint::new(vec![5, 4, 9, 3]) & BigUint::from(u128::MAX) - ); - - let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); - let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1])); - let q = k & i; - assert_eq!( - BigUint::from(&q), - BigUint::new(vec![5, 4, 9, 3, 1, 81]) & BigUint::new(vec![3, 9, 8, 3, 1]) +#[test] +#[cfg(feature = "num-bigint")] +fn test_op_and_i() { + run_tests_i_2( + |i, k| BigInt::from(&(i & k)), + |i, k| i & k, ); } #[test] #[cfg(feature = "num-bigint")] fn test_op_or_u() { - let i = SmallUint::from(u128::MAX); - let k = SmallUint::from(u128::MAX); - let q = i | k; - assert_eq!( - BigUint::from(&q), - BigUint::from(u128::MAX) | BigUint::from(u128::MAX) - ); - - let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); - let i = SmallUint::from(u128::MAX); - let q = k | i; - assert_eq!( - BigUint::from(&q), - BigUint::new(vec![5, 4, 9, 3, 1, 81]) | BigUint::from(u128::MAX) - ); - - let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); - let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1])); - let q = k | i; - assert_eq!( - BigUint::from(&q), - BigUint::new(vec![5, 4, 9, 3, 1, 81]) | BigUint::new(vec![3, 9, 8, 3, 1]) + run_tests_u_2( + |i, k| BigUint::from(&(i | k)), + |i, k| i | k, ); } #[test] #[cfg(feature = "num-bigint")] fn test_op_xor_u() { - let i = SmallUint::from(u128::MAX); - let k = SmallUint::from(u128::MAX); - let q = i ^ k; - assert_eq!( - BigUint::from(&q), - BigUint::from(u128::MAX) ^ BigUint::from(u128::MAX) - ); - - let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); - let i = SmallUint::from(u128::MAX); - let q = k ^ i; - assert_eq!( - BigUint::from(&q), - BigUint::new(vec![5, 4, 9, 3, 1, 81]) ^ BigUint::from(u128::MAX) - ); - - let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); - let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1])); - let q = k ^ i; - assert_eq!( - BigUint::from(&q), - BigUint::new(vec![5, 4, 9, 3, 1, 81]) ^ BigUint::new(vec![3, 9, 8, 3, 1]) + run_tests_u_2( + |i, k| BigUint::from(&(i ^ k)), + |i, k| i ^ k, ); } #[test] #[cfg(feature = "num-bigint")] fn test_op_neg() { - let i = SmallInt::from(u128::MAX); - let q = -i; - assert_eq!(BigInt::from(&q), -BigInt::from(u128::MAX)); - - let i = SmallInt::from(i128::MAX); - let q = -i; - assert_eq!(BigInt::from(&q), -BigInt::from(i128::MAX)); - - let i = SmallInt::from(i128::MIN); - let q = -i; - assert_eq!(BigInt::from(&q), -BigInt::from(i128::MIN)); + run_tests_i_1(|i| BigInt::from(&-i), |i| -i.clone()); } #[test] #[cfg(feature = "num-bigint")] fn test_conversion_sign_drop() { - let si = SmallInt::from(i128::MIN + 1); - let i = SmallUint::from_smallint_unsigned(si); - assert_eq!(BigUint::from(&i), BigUint::from(-(i128::MIN + 1) as u128)) + run_tests_i_1( + |i| BigUint::from(&SmallUint::from_smallint_unsigned(i)), + |i| i.magnitude().clone() + ); } #[test]