From f9eb2a1afa4fb6048fdef5193486fff1bca7ab7d Mon Sep 17 00:00:00 2001 From: EvilMuffinHa Date: Sun, 7 Aug 2022 18:35:36 -0400 Subject: [PATCH] all basic arith ops done (we don't talk about div) --- src/convert.rs | 15 +++++++++++++-- src/ops.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++--- src/tests.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 5 deletions(-) diff --git a/src/convert.rs b/src/convert.rs index d3098e7..8faf9c3 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -130,7 +130,14 @@ impl From for SmallInt { match s.0 { SmallUintType::Inline(i) => SmallInt::from(i), SmallUintType::Heap((r, s)) => { - SmallInt(SmallIntType::Heap((r, isize::try_from(s).unwrap()))) + let slice = unsafe { core::slice::from_raw_parts(r, s) }; + let mut ret = vec![0; s]; + ret.clone_from_slice(slice); + let mut val = ManuallyDrop::new(ret.into_boxed_slice()); + SmallInt(SmallIntType::Heap(( + val.as_mut_ptr(), + isize::try_from(s).unwrap(), + ))) } } } @@ -145,7 +152,11 @@ impl TryFrom for SmallUint { SmallIntType::Heap((r, s)) => { let size = usize::try_from(s).map_err(|_| SmallIntError::ConversionError)?; if size > 4 { - Ok(Self(SmallUintType::Heap((r, size)))) + let slice = unsafe { core::slice::from_raw_parts(r, size) }; + let mut ret = vec![0; size]; + ret.clone_from_slice(slice); + let mut val = ManuallyDrop::new(ret.into_boxed_slice()); + Ok(Self(SmallUintType::Heap((val.as_mut_ptr(), size)))) } else { Ok(Self(SmallUintType::Inline(u128::try_from(value)?))) } diff --git a/src/ops.rs b/src/ops.rs index 4c23c41..be7e3d7 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -171,9 +171,7 @@ fn add_signed(a: &SmallInt, b: &SmallInt) -> SmallInt { if b <= s { SmallInt::from(s - b) } else { - let v = b - s; - let r = SmallInt::from(v); - -r + -SmallInt::from(b - s) } } @@ -279,6 +277,12 @@ fn sub(a: &SmallUint, b: &SmallUint) -> SmallUint { basic_op!(Sub, sub, SmallUint, sub); +fn sub_signed(a: &SmallInt, b: &SmallInt) -> SmallInt { + a + (-b.clone()) +} + +basic_op!(Sub, sub, SmallInt, sub_signed); + // Taken from https://github.com/rust-lang/rust/issues/85532#issuecomment-916309635. Credit to // AaronKutch. const fn carrying_mul_u128(lhs: u128, rhs: u128, carry: u128) -> (u128, u128) { @@ -463,3 +467,44 @@ fn mul(a: &SmallUint, b: &SmallUint) -> SmallUint { } basic_op!(Mul, mul, SmallUint, mul); + +fn mul_signed(a: &SmallInt, b: &SmallInt) -> SmallInt { + let a_sign; + match &a.0 { + SmallIntType::Inline(i) => a_sign = i.signum() as i8, + SmallIntType::Heap((_, s)) => a_sign = s.signum() as i8, + } + + let b_sign; + match &b.0 { + SmallIntType::Inline(i) => b_sign = i.signum() as i8, + SmallIntType::Heap((_, s)) => b_sign = s.signum() as i8, + } + + match (a_sign, b_sign) { + x if (x.0 >= 0 && x.1 >= 0) => SmallInt::from( + SmallUint::from_smallint_unsigned(a.clone()) + * SmallUint::from_smallint_unsigned(b.clone()), + ), + x if (x.0 < 0 && x.1 < 0) => SmallInt::from( + SmallUint::from_smallint_unsigned(a.clone()) + * SmallUint::from_smallint_unsigned(b.clone()), + ), + + x if (x.0 >= 0 && x.1 < 0) => -SmallInt::from( + SmallUint::from_smallint_unsigned(a.clone()) + * SmallUint::from_smallint_unsigned(b.clone()), + ), + + x if (x.0 < 0 && x.1 >= 0) => -SmallInt::from( + SmallUint::from_smallint_unsigned(a.clone()) + * SmallUint::from_smallint_unsigned(b.clone()), + ), + + (_, _) => { + panic!("This shouldn't happen. "); + } + } +} + +basic_op!(Mul, mul, SmallInt, mul_signed); diff --git a/src/tests.rs b/src/tests.rs index e33e382..a8a3c8e 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -152,6 +152,32 @@ fn test_op_mul_u() { ); } +#[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]) + ); +} + #[test] #[cfg(feature = "num-bigint")] fn test_op_sub_u() { @@ -177,6 +203,32 @@ fn test_op_sub_u() { ); } +#[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])) + ); +} + #[test] #[cfg(feature = "num-bigint")] fn test_op_and_u() {