From 3510274fce84de98c23d671488718773b8fd9ff1 Mon Sep 17 00:00:00 2001 From: EvilMuffinHa Date: Fri, 5 Aug 2022 07:45:20 -0400 Subject: [PATCH 1/4] mul --- src/bigint.rs | 83 +++++++++ src/convert.rs | 155 ++++++++++++++++ src/error.rs | 15 ++ src/lib.rs | 483 +----------------------------------------------- src/ops.rs | 243 ++++++++++++++++++++++++ src/pretty.rs | 22 +++ src/smallint.rs | 43 +++++ src/tests.rs | 63 +++++++ 8 files changed, 634 insertions(+), 473 deletions(-) create mode 100644 src/bigint.rs create mode 100644 src/convert.rs create mode 100644 src/error.rs create mode 100644 src/ops.rs create mode 100644 src/pretty.rs create mode 100644 src/smallint.rs create mode 100644 src/tests.rs diff --git a/src/bigint.rs b/src/bigint.rs new file mode 100644 index 0000000..7725d46 --- /dev/null +++ b/src/bigint.rs @@ -0,0 +1,83 @@ +#![cfg(feature = "num-bigint")] + +use num_bigint::BigInt; +use num_bigint::BigUint; +use num_bigint::Sign; + +use core::mem::ManuallyDrop; + +use crate::SmallInt; +use crate::SmallUint; + +use crate::smallint::SmallIntType; +use crate::smallint::SmallUintType; + +impl From<&BigInt> for SmallInt { + fn from(b: &BigInt) -> Self { + match b.try_into() { + Ok(i) => Self(SmallIntType::Inline(i)), + Err(_) => { + let (sign, vec) = b.to_u32_digits(); + let mut slice = ManuallyDrop::new(vec.into_boxed_slice()); + let size = match sign { + Sign::Minus => -isize::try_from(slice.len()).unwrap(), + Sign::NoSign => panic!( + "Shouldn't happen; BigInts which store zero should convert to inline." + ), + Sign::Plus => isize::try_from(slice.len()).unwrap(), + }; + Self(SmallIntType::Heap((slice.as_mut_ptr(), size))) + } + } + } +} + +impl From<&SmallInt> for BigInt { + fn from(s: &SmallInt) -> Self { + match s.0 { + SmallIntType::Inline(i) => Self::from(i), + SmallIntType::Heap((r, s)) => { + let size = usize::try_from(s.abs()).unwrap(); + let sign = s.signum(); + let slice = unsafe { core::slice::from_raw_parts(r, size) }; + let bs = match sign { + 0 => Sign::NoSign, + -1 => Sign::Minus, + 1 => Sign::Plus, + _ => panic!("This shouldn't happen; There are only 3 signums."), + }; + + BigInt::new(bs, slice.to_vec()) + } + } + } +} + +impl From<&BigUint> for SmallUint { + fn from(b: &BigUint) -> Self { + match b.try_into() { + Ok(i) => Self(SmallUintType::Inline(i)), + Err(_) => { + let vec = b.to_u32_digits(); + let mut slice = ManuallyDrop::new(vec.into_boxed_slice()); + let size = slice.len(); + Self(SmallUintType::Heap((slice.as_mut_ptr(), size))) + } + } + } +} + +impl From<&SmallUint> for BigUint { + fn from(s: &SmallUint) -> Self { + match s.0 { + SmallUintType::Inline(i) => Self::from(i), + SmallUintType::Heap((r, s)) => { + let slice = unsafe { core::slice::from_raw_parts(r, s) }; + + BigUint::new(slice.to_vec()) + } + } + } +} + + diff --git a/src/convert.rs b/src/convert.rs new file mode 100644 index 0000000..f64b7dc --- /dev/null +++ b/src/convert.rs @@ -0,0 +1,155 @@ +use crate::SmallInt; +use crate::SmallUint; +use crate::SmallIntError; +use crate::smallint::{SmallIntType, SmallUintType}; +use core::mem::ManuallyDrop; + +macro_rules! int_impl { + ($itype:ty, $rt:tt, $rtt:tt, $n:tt) => { + impl From<$itype> for $rt { + fn from(a: $itype) -> Self { + Self(<$rtt>::Inline($n::from(a))) + } + } + + impl TryFrom<$rt> for $itype { + type Error = SmallIntError; + + fn try_from(s: $rt) -> Result { + match s.0 { + $rtt::Inline(i) => { + <$itype>::try_from(i).map_err(|_| SmallIntError::ConversionError) + } + $rtt::Heap((_, _)) => Err(SmallIntError::ConversionError), + } + } + } + }; +} + +int_impl!(u8, SmallInt, SmallIntType, i128); +int_impl!(u16, SmallInt, SmallIntType, i128); +int_impl!(u32, SmallInt, SmallIntType, i128); +int_impl!(u64, SmallInt, SmallIntType, i128); +int_impl!(i8, SmallInt, SmallIntType, i128); +int_impl!(i16, SmallInt, SmallIntType, i128); +int_impl!(i32, SmallInt, SmallIntType, i128); +int_impl!(i64, SmallInt, SmallIntType, i128); +int_impl!(i128, SmallInt, SmallIntType, i128); + +int_impl!(u8, SmallUint, SmallUintType, u128); +int_impl!(u16, SmallUint, SmallUintType, u128); +int_impl!(u32, SmallUint, SmallUintType, u128); +int_impl!(u64, SmallUint, SmallUintType, u128); +int_impl!(u128, SmallUint, SmallUintType, u128); + +macro_rules! try_from_itou { + ($itype:ty) => { + impl TryFrom<$itype> for SmallUint { + type Error = SmallIntError; + + fn try_from(a: $itype) -> Result { + Ok(Self(SmallUintType::Inline( + u128::try_from(a).map_err(|_| SmallIntError::ConversionError)?, + ))) + } + } + + impl TryFrom for $itype { + type Error = SmallIntError; + + fn try_from(s: SmallUint) -> Result { + match s.0 { + SmallUintType::Inline(i) => { + <$itype>::try_from(i).map_err(|_| SmallIntError::ConversionError) + } + SmallUintType::Heap((_, _)) => Err(SmallIntError::ConversionError), + } + } + } + }; +} + +try_from_itou!(i8); +try_from_itou!(i16); +try_from_itou!(i32); +try_from_itou!(i64); +try_from_itou!(i128); + +impl From for SmallInt { + fn from(a: u128) -> Self { + match i128::try_from(a) { + Ok(i) => Self(SmallIntType::Inline(i)), + Err(_) => { + let mut v = a; + let mut vec = Vec::with_capacity(4); + while v != 0 { + vec.push(v as u32); + + v >>= 32; + } + let mut slice = ManuallyDrop::new(vec.into_boxed_slice()); + Self(SmallIntType::Heap(( + slice.as_mut_ptr(), + isize::try_from(slice.len()).unwrap(), + ))) + } + } + } +} + +impl TryFrom for u128 { + type Error = SmallIntError; + + fn try_from(s: SmallInt) -> Result { + match s.0 { + SmallIntType::Inline(i) => { + u128::try_from(i).map_err(|_| SmallIntError::ConversionError) + } + SmallIntType::Heap((r, s)) => { + let mut ret: u128 = 0; + let mut bits = 0; + let size = usize::try_from(s.abs()).unwrap(); + let slice = unsafe { core::slice::from_raw_parts(r, size) }; + for i in slice { + if bits >= 128 { + return Err(SmallIntError::ConversionError); + } + ret |= u128::from(*i) << bits; + bits += 32; + } + + Ok(ret) + } + } + } +} + +impl From for SmallInt { + fn from(s: SmallUint) -> Self { + match s.0 { + SmallUintType::Inline(i) => SmallInt::from(i), + SmallUintType::Heap((r, s)) => { + SmallInt(SmallIntType::Heap((r, isize::try_from(s).unwrap()))) + } + } + } +} + +impl TryFrom for SmallUint { + type Error = SmallIntError; + + fn try_from(value: SmallInt) -> Result { + match value.0 { + SmallIntType::Inline(i) => Self::try_from(i), + SmallIntType::Heap((r, s)) => { + let size = usize::try_from(s).map_err(|_| SmallIntError::ConversionError)?; + if size > 4 { + Ok(Self(SmallUintType::Heap((r, size)))) + } else { + Ok(Self(SmallUintType::Inline(u128::try_from(value)?))) + } + } + } + } +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..f6d48d4 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,15 @@ +/// An error that occurred when processing a `SmallInt`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum SmallIntError { + /// Conversion error when converting from SmallInt to other integer types. + ConversionError, +} + +impl std::error::Error for SmallIntError {} + +impl core::fmt::Display for SmallIntError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let Self::ConversionError = self; + write!(f, "Error converting integer to SmallInt.") + } +} diff --git a/src/lib.rs b/src/lib.rs index 4c7289a..56b9710 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,483 +9,20 @@ // Invariant: If a small integer is on the heap, the size is the minimum digits required to // represent it. -#[cfg(feature = "num-bigint")] -use num_bigint::BigInt; +mod smallint; -#[cfg(feature = "num-bigint")] -use num_bigint::BigUint; +pub use crate::smallint::SmallInt; +pub use crate::smallint::SmallUint; -#[cfg(feature = "num-bigint")] -use num_bigint::Sign; +mod error; -use core::mem::ManuallyDrop; -use core::ops::Add; +pub use error::SmallIntError; -/// An error that occurred when processing a `SmallInt`. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum SmallIntError { - /// Conversion error when converting from SmallInt to other integer types. - ConversionError, -} +mod convert; +mod ops; -impl std::error::Error for SmallIntError {} +mod bigint; -impl core::fmt::Display for SmallIntError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let Self::ConversionError = self; - write!(f, "Error converting integer to SmallInt.") - } -} +mod pretty; -/// An integer-like type that will store small integers up to `i128` inline. Larger integers are -/// represented as a slice to a sequence of base 232 digits represented as a `*mut u32`. -#[derive(Clone, PartialEq, Eq)] -pub struct SmallInt(SmallIntType); - -/// An integer-like type that will store small integers up to `u128` inline. Larger integers are -/// represented as a slice to a sequence of base 232 digits represented as a `*mut u32`. -#[derive(Clone, PartialEq, Eq)] -pub struct SmallUint(SmallUintType); - -#[derive(Clone, PartialEq, Eq)] -enum SmallIntType { - Inline(i128), - Heap((*mut u32, isize)), -} - -#[derive(Clone, PartialEq, Eq)] -enum SmallUintType { - Inline(u128), - Heap((*mut u32, usize)), -} - -// TODO: Need to reimplement Debug, to_str_radix, and from_str_radix without num-bigint feature for -// SmallInt and SmallUint - -// TODO: add native operations for SmallInt and SmallUint - -#[cfg(feature = "num-bigint")] -impl core::fmt::Debug for SmallInt { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", BigInt::from(self)) - } -} - -#[cfg(feature = "num-bigint")] -impl core::fmt::Debug for SmallUint { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", BigUint::from(self)) - } -} - -fn add_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec { - - let s = slice1.len(); - let j = slice2.len(); - - let larger = std::cmp::max(s, j); - let mut res = Vec::with_capacity(larger + 1); - let mut carry = false; - - for t in 0..larger { - - let value1 = if t < s { - slice1[t] - } else { - 0 - }; - - let value2 = if t < j { - slice2[t] - } else { - 0 - }; - - let (val, overflow) = value1.overflowing_add(value2); - let (cval, coverflow) = val.overflowing_add(carry as u32); - res.push(cval); - carry = overflow | coverflow; - - } - - if carry { - res.push(1); - } - while res[res.len() - 1] == 0 { - res.pop(); - } - res -} - -impl Add for SmallUint { - type Output = SmallUint; - - fn add(self, rhs: SmallUint) -> Self::Output { - match (&self.0, &rhs.0) { - (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => { - match i.overflowing_add(j) { - (t, false) => Self(SmallUintType::Inline(t)), - (t, true) => { - let mut res = [0, 0, 0, 0, 1]; - - let mut v = t; - #[allow(clippy::needless_range_loop)] - for r in 0..4 { - res[r] = v as u32; - - v >>= 32; - } - - let mut slice = ManuallyDrop::new(>::from(res)); - - Self(SmallUintType::Heap((slice.as_mut_ptr(), 5))) - - } - } - }, - (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) | (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s))) => { - let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; - - let mut res = [0, 0, 0, 0]; - - let mut v = i; - #[allow(clippy::needless_range_loop)] - for r in 0..4 { - res[r] = v as u32; - - v >>= 32; - } - - let result = add_two_slices(slice1, &res[..]); - let size = result.len(); - - let mut slice = ManuallyDrop::new(result.into_boxed_slice()); - - Self(SmallUintType::Heap((slice.as_mut_ptr(), size))) - - - }, - (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => { - - let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; - let slice2 = unsafe { core::slice::from_raw_parts(i, j) }; - - let res = add_two_slices(slice1, slice2); - let size = res.len(); - - let mut slice = ManuallyDrop::new(res.into_boxed_slice()); - - Self(SmallUintType::Heap((slice.as_mut_ptr(), size))) - - } - } - } -} - - -impl Drop for SmallInt { - fn drop(&mut self) { - if let Self(SmallIntType::Heap((r, s))) = self { - let size = usize::try_from(s.abs()).unwrap(); - let slice = unsafe { core::slice::from_raw_parts_mut(*r, size) }; - unsafe { std::mem::drop(Box::from_raw(slice)) } - } - } -} - -impl Drop for SmallUint { - fn drop(&mut self) { - if let Self(SmallUintType::Heap((r, s))) = self { - let slice = unsafe { core::slice::from_raw_parts_mut(*r, *s) }; - unsafe { std::mem::drop(Box::from_raw(slice)) } - } - } -} - -macro_rules! int_impl { - ($itype:ty, $rt:tt, $rtt:tt, $n:tt) => { - impl From<$itype> for $rt { - fn from(a: $itype) -> Self { - Self(<$rtt>::Inline($n::from(a))) - } - } - - impl TryFrom<$rt> for $itype { - type Error = SmallIntError; - - fn try_from(s: $rt) -> Result { - match s.0 { - $rtt::Inline(i) => { - <$itype>::try_from(i).map_err(|_| SmallIntError::ConversionError) - } - $rtt::Heap((_, _)) => Err(SmallIntError::ConversionError), - } - } - } - }; -} - -int_impl!(u8, SmallInt, SmallIntType, i128); -int_impl!(u16, SmallInt, SmallIntType, i128); -int_impl!(u32, SmallInt, SmallIntType, i128); -int_impl!(u64, SmallInt, SmallIntType, i128); -int_impl!(i8, SmallInt, SmallIntType, i128); -int_impl!(i16, SmallInt, SmallIntType, i128); -int_impl!(i32, SmallInt, SmallIntType, i128); -int_impl!(i64, SmallInt, SmallIntType, i128); -int_impl!(i128, SmallInt, SmallIntType, i128); - -int_impl!(u8, SmallUint, SmallUintType, u128); -int_impl!(u16, SmallUint, SmallUintType, u128); -int_impl!(u32, SmallUint, SmallUintType, u128); -int_impl!(u64, SmallUint, SmallUintType, u128); -int_impl!(u128, SmallUint, SmallUintType, u128); - -macro_rules! try_from_itou { - ($itype:ty) => { - impl TryFrom<$itype> for SmallUint { - type Error = SmallIntError; - - fn try_from(a: $itype) -> Result { - Ok(Self(SmallUintType::Inline( - u128::try_from(a).map_err(|_| SmallIntError::ConversionError)?, - ))) - } - } - - impl TryFrom for $itype { - type Error = SmallIntError; - - fn try_from(s: SmallUint) -> Result { - match s.0 { - SmallUintType::Inline(i) => { - <$itype>::try_from(i).map_err(|_| SmallIntError::ConversionError) - } - SmallUintType::Heap((_, _)) => Err(SmallIntError::ConversionError), - } - } - } - }; -} - -try_from_itou!(i8); -try_from_itou!(i16); -try_from_itou!(i32); -try_from_itou!(i64); -try_from_itou!(i128); - -impl From for SmallInt { - fn from(a: u128) -> Self { - match i128::try_from(a) { - Ok(i) => Self(SmallIntType::Inline(i)), - Err(_) => { - let mut v = a; - let mut vec = Vec::with_capacity(4); - while v != 0 { - vec.push(v as u32); - - v >>= 32; - } - let mut slice = ManuallyDrop::new(vec.into_boxed_slice()); - Self(SmallIntType::Heap(( - slice.as_mut_ptr(), - isize::try_from(slice.len()).unwrap(), - ))) - } - } - } -} - -impl TryFrom for u128 { - type Error = SmallIntError; - - fn try_from(s: SmallInt) -> Result { - match s.0 { - SmallIntType::Inline(i) => { - u128::try_from(i).map_err(|_| SmallIntError::ConversionError) - } - SmallIntType::Heap((r, s)) => { - let mut ret: u128 = 0; - let mut bits = 0; - let size = usize::try_from(s.abs()).unwrap(); - let slice = unsafe { core::slice::from_raw_parts(r, size) }; - for i in slice { - if bits >= 128 { - return Err(SmallIntError::ConversionError); - } - ret |= u128::from(*i) << bits; - bits += 32; - } - - Ok(ret) - } - } - } -} - -impl From for SmallInt { - fn from(s: SmallUint) -> Self { - match s.0 { - SmallUintType::Inline(i) => SmallInt::from(i), - SmallUintType::Heap((r, s)) => { - SmallInt(SmallIntType::Heap((r, isize::try_from(s).unwrap()))) - } - } - } -} - -impl TryFrom for SmallUint { - type Error = SmallIntError; - - fn try_from(value: SmallInt) -> Result { - match value.0 { - SmallIntType::Inline(i) => Self::try_from(i), - SmallIntType::Heap((r, s)) => { - let size = usize::try_from(s).map_err(|_| SmallIntError::ConversionError)?; - if size > 4 { - Ok(Self(SmallUintType::Heap((r, size)))) - } else { - Ok(Self(SmallUintType::Inline(u128::try_from(value)?))) - } - } - } - } -} - -#[cfg(feature = "num-bigint")] -impl From<&BigInt> for SmallInt { - fn from(b: &BigInt) -> Self { - match b.try_into() { - Ok(i) => Self(SmallIntType::Inline(i)), - Err(_) => { - let (sign, vec) = b.to_u32_digits(); - let mut slice = ManuallyDrop::new(vec.into_boxed_slice()); - let size = match sign { - Sign::Minus => -isize::try_from(slice.len()).unwrap(), - Sign::NoSign => panic!( - "Shouldn't happen; BigInts which store zero should convert to inline." - ), - Sign::Plus => isize::try_from(slice.len()).unwrap(), - }; - Self(SmallIntType::Heap((slice.as_mut_ptr(), size))) - } - } - } -} - -#[cfg(feature = "num-bigint")] -impl From<&SmallInt> for BigInt { - fn from(s: &SmallInt) -> Self { - match s.0 { - SmallIntType::Inline(i) => Self::from(i), - SmallIntType::Heap((r, s)) => { - let size = usize::try_from(s.abs()).unwrap(); - let sign = s.signum(); - let slice = unsafe { core::slice::from_raw_parts(r, size) }; - let bs = match sign { - 0 => Sign::NoSign, - -1 => Sign::Minus, - 1 => Sign::Plus, - _ => panic!("This shouldn't happen; There are only 3 signums."), - }; - - BigInt::new(bs, slice.to_vec()) - } - } - } -} - -#[cfg(feature = "num-bigint")] -impl From<&BigUint> for SmallUint { - fn from(b: &BigUint) -> Self { - match b.try_into() { - Ok(i) => Self(SmallUintType::Inline(i)), - Err(_) => { - let vec = b.to_u32_digits(); - let mut slice = ManuallyDrop::new(vec.into_boxed_slice()); - let size = slice.len(); - Self(SmallUintType::Heap((slice.as_mut_ptr(), size))) - } - } - } -} - -#[cfg(feature = "num-bigint")] -impl From<&SmallUint> for BigUint { - fn from(s: &SmallUint) -> Self { - match s.0 { - SmallUintType::Inline(i) => Self::from(i), - SmallUintType::Heap((r, s)) => { - let slice = unsafe { core::slice::from_raw_parts(r, s) }; - - BigUint::new(slice.to_vec()) - } - } - } -} - -#[cfg(test)] -mod conversion_tests { - - use crate::SmallInt; - use crate::SmallUint; - - #[cfg(feature = "num-bigint")] - use num_bigint::{BigInt, Sign, BigUint}; - - macro_rules! conversion_tests { - ($t:ty, $i:ident) => { - #[test] - fn $i() { - let i = <$t>::MAX; - let s = SmallInt::from(i); - assert_eq!(<$t>::try_from(s).unwrap(), i); - - let i = <$t>::MIN; - let s = SmallInt::from(i); - assert_eq!(<$t>::try_from(s).unwrap(), i); - } - }; - } - - conversion_tests!(u8, test_u8); - conversion_tests!(i8, test_i8); - conversion_tests!(u16, test_u16); - conversion_tests!(i16, test_i16); - conversion_tests!(u32, test_u32); - conversion_tests!(i32, test_i32); - conversion_tests!(u64, test_u64); - conversion_tests!(i64, test_i64); - conversion_tests!(u128, test_u128); - conversion_tests!(i128, test_i128); - - #[test] - #[cfg(feature = "num-bigint")] - fn test_op_add_u_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])); - 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]) + BigUint::new(vec![5, 4, 9, 3, 1, 81])); - } - - #[test] - #[cfg(feature = "num-bigint")] - fn test_bigint() { - let i = BigInt::new(Sign::Plus, vec![5, 4, 8, 3, 2, 9, 3]); - let s = SmallInt::from(&i); - assert_eq!( - BigInt::from(&s).to_u32_digits(), - (Sign::Plus, vec![5, 4, 8, 3, 2, 9, 3]) - ); - } -} +mod tests; diff --git a/src/ops.rs b/src/ops.rs new file mode 100644 index 0000000..cb50c2e --- /dev/null +++ b/src/ops.rs @@ -0,0 +1,243 @@ +use crate::SmallUint; +use crate::smallint::SmallUintType; +use core::ops::Add; +use core::mem::ManuallyDrop; + +macro_rules! basic_op { + ($imp:ident, $typ:ty, $fun:ident) => { + + impl<'a, 'b> $imp<&'a $typ> for &'b $typ { + + type Output = $typ; + + fn $fun(self, rhs: &$typ) -> Self::Output { + $fun(self, rhs) + } + + } + + impl<'a> $imp<$typ> for &'a $typ { + + type Output = $typ; + + fn $fun(self, rhs: $typ) -> Self::Output { + self.$fun(&rhs) + } + + } + + impl<'a> $imp<&'a $typ> for $typ { + + type Output = $typ; + + fn $fun(self, rhs: &$typ) -> Self::Output { + (&self).$fun(rhs) + } + + } + + + impl $imp<$typ> for $typ { + + type Output = $typ; + + fn $fun(self, rhs: $typ) -> Self::Output { + (&self).$fun(&rhs) + } + + } + } +} + + +fn add_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec { + + let s = slice1.len(); + let j = slice2.len(); + + let larger = std::cmp::max(s, j); + let mut res = Vec::with_capacity(larger + 1); + let mut carry = false; + + for t in 0..larger { + + let value1 = if t < s { + slice1[t] + } else { + 0 + }; + + let value2 = if t < j { + slice2[t] + } else { + 0 + }; + + let (val, overflow) = value1.overflowing_add(value2); + let (cval, coverflow) = val.overflowing_add(carry as u32); + res.push(cval); + carry = overflow | coverflow; + + } + + if carry { + res.push(1); + } + while res[res.len() - 1] == 0 { + res.pop(); + } + res +} + +fn add(a: &SmallUint, b: &SmallUint) -> SmallUint { + + match (&a.0, &b.0) { + (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => { + match i.overflowing_add(j) { + (t, false) => SmallUint(SmallUintType::Inline(t)), + (t, true) => { + let mut res = [0, 0, 0, 0, 1]; + + let mut v = t; + #[allow(clippy::needless_range_loop)] + for r in 0..4 { + res[r] = v as u32; + + v >>= 32; + } + + let mut slice = ManuallyDrop::new(>::from(res)); + + SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), 5))) + + } + } + }, + (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) | (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s))) => { + let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; + + let mut res = [0, 0, 0, 0]; + + let mut v = i; + #[allow(clippy::needless_range_loop)] + for r in 0..4 { + res[r] = v as u32; + + v >>= 32; + } + + let result = add_two_slices(slice1, &res[..]); + let size = result.len(); + + let mut slice = ManuallyDrop::new(result.into_boxed_slice()); + + SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) + + + }, + (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => { + + let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; + let slice2 = unsafe { core::slice::from_raw_parts(i, j) }; + + let res = add_two_slices(slice1, slice2); + let size = res.len(); + + let mut slice = ManuallyDrop::new(res.into_boxed_slice()); + + SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) + + } + } +} + +basic_op!(Add, SmallUint, add); + +// 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) { + // [rhs_hi] [rhs_lo] + // [lhs_hi] [lhs_lo] + // X___________________ + // [------tmp0------] + // [------tmp1------] + // [------tmp2------] + // [------tmp3------] + // [-------add------] + // +_______________________________________ + // [------sum0------] + // [------sum1------] + + let lhs_lo = lhs as u64; + let rhs_lo = rhs as u64; + let lhs_hi = (lhs.wrapping_shr(64)) as u64; + let rhs_hi = (rhs.wrapping_shr(64)) as u64; + let tmp0 = (lhs_lo as u128).wrapping_mul(rhs_lo as u128); + let tmp1 = (lhs_lo as u128).wrapping_mul(rhs_hi as u128); + let tmp2 = (lhs_hi as u128).wrapping_mul(rhs_lo as u128); + let tmp3 = (lhs_hi as u128).wrapping_mul(rhs_hi as u128); + // tmp1 and tmp2 straddle the boundary. We have to handle three carries + let (sum0, carry0) = tmp0.overflowing_add(tmp1.wrapping_shl(64)); + let (sum0, carry1) = sum0.overflowing_add(tmp2.wrapping_shl(64)); + let (sum0, carry2) = sum0.overflowing_add(carry); + let sum1 = tmp3 + .wrapping_add(tmp1.wrapping_shr(64)) + .wrapping_add(tmp2.wrapping_shr(64)) + .wrapping_add(carry0 as u128) + .wrapping_add(carry1 as u128) + .wrapping_add(carry2 as u128); + (sum0, sum1) +} + +// fn mul_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec { +// +// let l1 = slice1.len(); +// let l2 = slice2.len(); +// +// +// } +// +// +// fn mul(a: &SmallUint, b: &SmallUint) -> SmallUint { +// match (&a.0, &b.0) { +// (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => { +// match carrying_mul_u128(i, j, 0) { +// (t, 0) => SmallUint(SmallUintType::Inline(t)), +// (t, o) => { +// let mut res = Vec::with_capacity(8); +// +// let mut v = t; +// #[allow(clippy::needless_range_loop)] +// for _ in 0..4 { +// res.push(v as u32); +// +// v >>= 32; +// } +// +// let mut v = o; +// for _ in 4..8 { +// res.push(v as u32); +// +// v >>= 32; +// } +// +// while res[res.len() - 1] == 0 { +// res.pop(); +// } +// +// let size = res.len(); +// +// let mut slice = ManuallyDrop::new(res.into_boxed_slice()); +// +// SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) +// +// } +// } +// }, +// (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) | (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s))) => { +// +// } +// } +// } +// +// diff --git a/src/pretty.rs b/src/pretty.rs new file mode 100644 index 0000000..be22ad9 --- /dev/null +++ b/src/pretty.rs @@ -0,0 +1,22 @@ +use crate::SmallInt; +use crate::SmallUint; + + +#[cfg(feature= "num-bigint")] +use num_bigint::{BigInt, BigUint}; + + +#[cfg(feature = "num-bigint")] +impl core::fmt::Debug for SmallInt { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", BigInt::from(self)) + } +} + +#[cfg(feature = "num-bigint")] +impl core::fmt::Debug for SmallUint { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", BigUint::from(self)) + } +} + diff --git a/src/smallint.rs b/src/smallint.rs new file mode 100644 index 0000000..dabff1e --- /dev/null +++ b/src/smallint.rs @@ -0,0 +1,43 @@ + +/// An integer-like type that will store small integers up to `i128` inline. Larger integers are +/// represented as a slice to a sequence of base 232 digits represented as a `*mut u32`. +#[derive(Clone, PartialEq, Eq)] +pub struct SmallInt(pub(crate) SmallIntType); + +/// An integer-like type that will store small integers up to `u128` inline. Larger integers are +/// represented as a slice to a sequence of base 232 digits represented as a `*mut u32`. +#[derive(Clone, PartialEq, Eq)] +pub struct SmallUint(pub(crate) SmallUintType); + +#[derive(Clone, PartialEq, Eq)] +pub enum SmallIntType { + Inline(i128), + Heap((*mut u32, isize)), +} + +#[derive(Clone, PartialEq, Eq)] +pub enum SmallUintType { + Inline(u128), + Heap((*mut u32, usize)), +} + + +impl Drop for SmallInt { + fn drop(&mut self) { + if let Self(SmallIntType::Heap((r, s))) = self { + let size = usize::try_from(s.abs()).unwrap(); + let slice = unsafe { core::slice::from_raw_parts_mut(*r, size) }; + unsafe { std::mem::drop(Box::from_raw(slice)) } + } + } +} + +impl Drop for SmallUint { + fn drop(&mut self) { + if let Self(SmallUintType::Heap((r, s))) = self { + let slice = unsafe { core::slice::from_raw_parts_mut(*r, *s) }; + unsafe { std::mem::drop(Box::from_raw(slice)) } + } + } +} + diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..fc95bc9 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,63 @@ +#![cfg(test)] + +use crate::SmallInt; +use crate::SmallUint; + +#[cfg(feature = "num-bigint")] +use num_bigint::{BigInt, Sign, BigUint}; + +macro_rules! conversion_tests { + ($t:ty, $i:ident) => { + #[test] + fn $i() { + let i = <$t>::MAX; + let s = SmallInt::from(i); + assert_eq!(<$t>::try_from(s).unwrap(), i); + + let i = <$t>::MIN; + let s = SmallInt::from(i); + assert_eq!(<$t>::try_from(s).unwrap(), i); + } + }; +} + +conversion_tests!(u8, test_u8); +conversion_tests!(i8, test_i8); +conversion_tests!(u16, test_u16); +conversion_tests!(i16, test_i16); +conversion_tests!(u32, test_u32); +conversion_tests!(i32, test_i32); +conversion_tests!(u64, test_u64); +conversion_tests!(i64, test_i64); +conversion_tests!(u128, test_u128); +conversion_tests!(i128, test_i128); + +#[test] +#[cfg(feature = "num-bigint")] +fn test_op_add_u_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])); + 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]) + BigUint::new(vec![5, 4, 9, 3, 1, 81])); +} + +#[test] +#[cfg(feature = "num-bigint")] +fn test_bigint() { + let i = BigInt::new(Sign::Plus, vec![5, 4, 8, 3, 2, 9, 3]); + let s = SmallInt::from(&i); + assert_eq!( + BigInt::from(&s).to_u32_digits(), + (Sign::Plus, vec![5, 4, 8, 3, 2, 9, 3]) + ); +} From 4d6017b97493ebd3ab28b4143184d899a1c84d47 Mon Sep 17 00:00:00 2001 From: EvilMuffinHa Date: Sat, 6 Aug 2022 00:08:25 -0400 Subject: [PATCH 2/4] karatsuba multiplication: doesn't work yet --- src/ops.rs | 313 ++++++++++++++++++++++++++++++++++++++++++--------- src/tests.rs | 46 +++++++- 2 files changed, 303 insertions(+), 56 deletions(-) diff --git a/src/ops.rs b/src/ops.rs index cb50c2e..d197bc5 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -1,6 +1,6 @@ use crate::SmallUint; use crate::smallint::SmallUintType; -use core::ops::Add; +use core::ops::{Add, Sub, Mul}; use core::mem::ManuallyDrop; macro_rules! basic_op { @@ -83,12 +83,13 @@ fn add_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec { if carry { res.push(1); } - while res[res.len() - 1] == 0 { + while res.len() != 1 && res[res.len() - 1] == 0 { res.pop(); } res } + fn add(a: &SmallUint, b: &SmallUint) -> SmallUint { match (&a.0, &b.0) { @@ -153,6 +154,103 @@ fn add(a: &SmallUint, b: &SmallUint) -> SmallUint { basic_op!(Add, SmallUint, add); +fn sub_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec { + let b = slice1.len(); + let s = slice2.len(); + + if b < s { + panic!("First number is smaller than second."); + } + + let mut res = Vec::with_capacity(std::cmp::max(s, b)); + let mut borrow = false; + + for i in 0..b { + let mut value1 = slice1[i]; + + let value2 = if i < s { + slice2[i] + } else { + 0 + }; + + if borrow { + let (temp, b) = value1.overflowing_sub(1); + value1 = temp; + borrow = b; + } + + if value2 > value1 { + borrow = true; + } + + let val = value1.wrapping_sub(value2); + res.push(val); + + } + + if borrow { + panic!("First number is smaller than second. "); + } + + res + +} + +fn sub(a: &SmallUint, b: &SmallUint) -> SmallUint { + + match (&a.0, &b.0) { + (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => { + if let (t, false) = i.overflowing_sub(j) { + SmallUint(SmallUintType::Inline(t)) + } else { + panic!("First number is smaller than second. "); + } + }, + (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => { + let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; + + let mut res = [0, 0, 0, 0]; + + let mut v = i; + #[allow(clippy::needless_range_loop)] + for r in 0..4 { + res[r] = v as u32; + + v >>= 32; + } + + let result = sub_two_slices(slice1, &res[..]); + let size = result.len(); + + let mut slice = ManuallyDrop::new(result.into_boxed_slice()); + + SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) + + + }, + (&SmallUintType::Inline(_), &SmallUintType::Heap((_, _))) => { + panic!("First number is smaller than second. "); + + }, + (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => { + + let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; + let slice2 = unsafe { core::slice::from_raw_parts(i, j) }; + + let res = sub_two_slices(slice1, slice2); + let size = res.len(); + + let mut slice = ManuallyDrop::new(res.into_boxed_slice()); + + SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) + + } + } +} + +basic_op!(Sub, SmallUint, sub); + // 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) { @@ -189,55 +287,162 @@ const fn carrying_mul_u128(lhs: u128, rhs: u128, carry: u128) -> (u128, u128) { (sum0, sum1) } -// fn mul_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec { -// -// let l1 = slice1.len(); -// let l2 = slice2.len(); -// -// -// } -// -// -// fn mul(a: &SmallUint, b: &SmallUint) -> SmallUint { -// match (&a.0, &b.0) { -// (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => { -// match carrying_mul_u128(i, j, 0) { -// (t, 0) => SmallUint(SmallUintType::Inline(t)), -// (t, o) => { -// let mut res = Vec::with_capacity(8); -// -// let mut v = t; -// #[allow(clippy::needless_range_loop)] -// for _ in 0..4 { -// res.push(v as u32); -// -// v >>= 32; -// } -// -// let mut v = o; -// for _ in 4..8 { -// res.push(v as u32); -// -// v >>= 32; -// } -// -// while res[res.len() - 1] == 0 { -// res.pop(); -// } -// -// let size = res.len(); -// -// let mut slice = ManuallyDrop::new(res.into_boxed_slice()); -// -// SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) -// -// } -// } -// }, -// (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) | (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s))) => { -// -// } -// } -// } -// -// +fn mul_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec { + + // https://en.wikipedia.org/wiki/Karatsuba_algorithm + + let l1 = slice1.len(); + let l2 = slice2.len(); + + + if l1 == 0 || l2 == 0 { + return vec![]; + } else if l1 == 1 { + let mut overflow = 0; + let mut res: Vec = Vec::with_capacity(l2 + 1); + + #[allow(clippy::needless_range_loop)] + for i in 0..l2 { + let mut r = (slice2[i] as u64) * (slice1[0] as u64); + r += overflow as u64; + let m = r as u32; + overflow = (r >> 32) as u32; + res.push(m); + + } + + if overflow != 0 { + res.push(overflow); + } + + return res; + } else if l2 == 1 { + + let mut overflow = 0; + let mut res: Vec = Vec::with_capacity(l2 + 1); + + #[allow(clippy::needless_range_loop)] + for i in 0..l1 { + let mut r = (slice1[i] as u64) * (slice2[0] as u64); + r += overflow as u64; + let m = r as u32; + overflow = (r >> 32) as u32; + res.push(m); + + } + + if overflow != 0 { + res.push(overflow); + } + + return res; + } + + let m = std::cmp::min(l1, l2); + let m2 = (m as u32) / 2; + + let (low1, high1) = slice1.split_at(m2 as usize); + let (low2, high2) = slice2.split_at(m2 as usize); + + println!("z0: {:?}, {:?}", low1, low2); + println!("z1: {:?}, {:?}", &add_two_slices(low1, high1), &add_two_slices(low2, high2)); + println!("z2: {:?}, {:?}", high1, high2); + + let z0 = mul_two_slices(low1, low2); + let z1 = mul_two_slices(&add_two_slices(low1, high1), &add_two_slices(low2, high2)); + let z2 = mul_two_slices(high1, high2); + + let mut op0 = z0.clone(); + + for _ in 0..(m2 * 2) { + op0.insert(0, 0); + } + + let mut op1 = sub_two_slices(&sub_two_slices(&z1, &z2), &z0); + + for _ in 0..m2 { + op1.insert(0, 0); + } + + add_two_slices(&add_two_slices(&op0, &op1), &z0) + +} + + +fn mul(a: &SmallUint, b: &SmallUint) -> SmallUint { + match (&a.0, &b.0) { + (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => { + match carrying_mul_u128(i, j, 0) { + (t, 0) => SmallUint(SmallUintType::Inline(t)), + (t, o) => { + let mut res = Vec::with_capacity(8); + + let mut v = t; + #[allow(clippy::needless_range_loop)] + for _ in 0..4 { + res.push(v as u32); + + v >>= 32; + } + + let mut v = o; + for _ in 4..8 { + res.push(v as u32); + + v >>= 32; + } + + while res[res.len() - 1] == 0 { + res.pop(); + } + + let size = res.len(); + + let mut slice = ManuallyDrop::new(res.into_boxed_slice()); + + SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) + + } + } + }, + + (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) | (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s))) => { + let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; + + let mut res = [0, 0, 0, 0]; + + let mut v = i; + #[allow(clippy::needless_range_loop)] + for r in 0..4 { + res[r] = v as u32; + + v >>= 32; + } + + let result = mul_two_slices(slice1, &res[..]); + let size = result.len(); + + let mut slice = ManuallyDrop::new(result.into_boxed_slice()); + + SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) + + + }, + (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => { + + let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; + let slice2 = unsafe { core::slice::from_raw_parts(i, j) }; + + let res = mul_two_slices(slice1, slice2); + let size = res.len(); + + let mut slice = ManuallyDrop::new(res.into_boxed_slice()); + + SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) + + } + } +} + +basic_op!(Mul, SmallUint, mul); + diff --git a/src/tests.rs b/src/tests.rs index fc95bc9..7e4818b 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -45,12 +45,54 @@ fn test_op_add_u_u() { 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])); + 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]) + BigUint::new(vec![5, 4, 9, 3, 1, 81])); + assert_eq!(BigUint::from(&q), BigUint::new(vec![3, 9, 8, 3, 1]) + BigUint::new(vec![5, 4, 9, 3, 1, 81])); } +#[test] +#[cfg(feature = "num-bigint")] +fn test_op_mul_u_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])); + +} + +#[test] +#[cfg(feature = "num-bigint")] +fn test_op_sub_u_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])); + +} + + #[test] #[cfg(feature = "num-bigint")] fn test_bigint() { From 543b4ef459498fc96b8dd9a49cd653d4d7a3d6c7 Mon Sep 17 00:00:00 2001 From: EvilMuffinHa Date: Sat, 6 Aug 2022 00:16:39 -0400 Subject: [PATCH 3/4] karatsuba fixed --- src/ops.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ops.rs b/src/ops.rs index d197bc5..bba35bd 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -344,25 +344,27 @@ fn mul_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec { let (low1, high1) = slice1.split_at(m2 as usize); let (low2, high2) = slice2.split_at(m2 as usize); - println!("z0: {:?}, {:?}", low1, low2); - println!("z1: {:?}, {:?}", &add_two_slices(low1, high1), &add_two_slices(low2, high2)); - println!("z2: {:?}, {:?}", high1, high2); - let z0 = mul_two_slices(low1, low2); let z1 = mul_two_slices(&add_two_slices(low1, high1), &add_two_slices(low2, high2)); let z2 = mul_two_slices(high1, high2); - let mut op0 = z0.clone(); + let mut op0 = z2.clone(); + + op0.reverse(); + + op0.resize(op0.len() + (m2 as usize * 2), 0); + + op0.reverse(); + - for _ in 0..(m2 * 2) { - op0.insert(0, 0); - } let mut op1 = sub_two_slices(&sub_two_slices(&z1, &z2), &z0); - - for _ in 0..m2 { - op1.insert(0, 0); - } + + op1.reverse(); + + op1.resize(op1.len() + (m2 as usize), 0); + + op1.reverse(); add_two_slices(&add_two_slices(&op0, &op1), &z0) From 85babc5e1107703a59798a0e3e429fc3fa50fc85 Mon Sep 17 00:00:00 2001 From: EvilMuffinHa Date: Sat, 6 Aug 2022 16:38:22 -0400 Subject: [PATCH 4/4] basic logic for smalluint --- src/lib.rs | 1 + src/logic.rs | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/ops.rs | 1 + src/tests.rs | 61 ++++++++++++++ 4 files changed, 282 insertions(+) create mode 100644 src/logic.rs diff --git a/src/lib.rs b/src/lib.rs index 56b9710..2de2b64 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ pub use error::SmallIntError; mod convert; mod ops; +mod logic; mod bigint; diff --git a/src/logic.rs b/src/logic.rs new file mode 100644 index 0000000..c678d80 --- /dev/null +++ b/src/logic.rs @@ -0,0 +1,219 @@ +use crate::SmallUint; +use crate::smallint::SmallUintType; +use core::ops::{BitAnd, BitOr, BitXor}; +use core::mem::ManuallyDrop; + +macro_rules! basic_op { + ($imp:ident, $typ:ty, $fun:ident) => { + + impl<'a, 'b> $imp<&'a $typ> for &'b $typ { + + type Output = $typ; + + fn $fun(self, rhs: &$typ) -> Self::Output { + $fun(self, rhs) + } + + } + + impl<'a> $imp<$typ> for &'a $typ { + + type Output = $typ; + + fn $fun(self, rhs: $typ) -> Self::Output { + self.$fun(&rhs) + } + + } + + impl<'a> $imp<&'a $typ> for $typ { + + type Output = $typ; + + fn $fun(self, rhs: &$typ) -> Self::Output { + (&self).$fun(rhs) + } + + } + + + impl $imp<$typ> for $typ { + + type Output = $typ; + + fn $fun(self, rhs: $typ) -> Self::Output { + (&self).$fun(&rhs) + } + + } + } +} + +fn bitand(a: &SmallUint, b: &SmallUint) -> SmallUint { + match (&a.0, &b.0) { + (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => { + SmallUint(SmallUintType::Inline(i & j)) + }, + + (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s))) | (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => { + let slice = unsafe { core::slice::from_raw_parts(r, s) }; + let mut j = 0u128; + for i in 0..4 { + j <<= 32; + + j |= slice[3 - i] as u128; + + } + SmallUint(SmallUintType::Inline(i & j)) + }, + + (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => { + + let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; + let slice2 = unsafe { core::slice::from_raw_parts(i, j) }; + + let min = std::cmp::min(slice1.len(), slice2.len()); + + let mut res = Vec::with_capacity(min); + + for l in 0..min { + res.push(slice1[l] & slice2[l]); + } + + while res.len() != 1 && res[res.len() - 1] == 0 { + res.pop(); + } + + if res.len() <= 4 { + let mut r = 0u128; + for t in 0..res.len() { + r <<= 32; + r |= res[res.len() - 1 - t] as u128; + } + SmallUint(SmallUintType::Inline(r)) + } else { + let mut slice = ManuallyDrop::new(res.into_boxed_slice()); + SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), slice.len()))) + } + } + } +} + +basic_op!(BitAnd, SmallUint, bitand); + +fn bitor(a: &SmallUint, b: &SmallUint) -> SmallUint { + match (&a.0, &b.0) { + (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => { + SmallUint(SmallUintType::Inline(i | j)) + }, + (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s))) | (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => { + let slice = unsafe { core::slice::from_raw_parts(r, s) }; + + let mut retvec = slice.to_vec(); + + let mut v = i; + #[allow(clippy::needless_range_loop)] + for r in 0..4 { + retvec[r] |= v as u32; + + v >>= 32; + } + + let mut retslice = ManuallyDrop::new(retvec.into_boxed_slice()); + + SmallUint(SmallUintType::Heap((retslice.as_mut_ptr(), retslice.len()))) + + } + + (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => { + + let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; + let slice2 = unsafe { core::slice::from_raw_parts(i, j) }; + + let m = std::cmp::min(slice1.len(), slice2.len()); + + let mut retvec; + if slice1.len() > slice2.len() { + retvec = slice1.to_vec(); + } else { + retvec = slice2.to_vec(); + } + + for t in 0..m { + retvec[t] = slice1[t] | slice2[t]; + } + + let mut slice = ManuallyDrop::new(retvec.into_boxed_slice()); + + SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), slice.len()))) + + } + + } +} + +basic_op!(BitOr, SmallUint, bitor); + +fn bitxor(a: &SmallUint, b: &SmallUint) -> SmallUint { + match (&a.0, &b.0) { + (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => { + SmallUint(SmallUintType::Inline(i ^ j)) + } + (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s))) | (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => { + let slice = unsafe { core::slice::from_raw_parts(r, s) }; + + let mut retvec = slice.to_vec(); + + let mut v = i; + #[allow(clippy::needless_range_loop)] + for r in 0..4 { + retvec[r] ^= v as u32; + + v >>= 32; + } + + let mut retslice = ManuallyDrop::new(retvec.into_boxed_slice()); + + SmallUint(SmallUintType::Heap((retslice.as_mut_ptr(), retslice.len()))) + + + }, + + (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => { + + let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; + let slice2 = unsafe { core::slice::from_raw_parts(i, j) }; + + let m = std::cmp::min(slice1.len(), slice2.len()); + + let mut res; + if slice1.len() > slice2.len() { + res = slice1.to_vec(); + } else { + res = slice2.to_vec(); + } + + for t in 0..m { + res[t] = slice1[t] ^ slice2[t]; + } + + while res.len() != 1 && res[res.len() - 1] == 0 { + res.pop(); + } + + if res.len() <= 4 { + let mut r = 0u128; + for t in 0..res.len() { + r <<= 32; + r |= res[res.len() - 1 - t] as u128; + } + SmallUint(SmallUintType::Inline(r)) + } else { + let mut slice = ManuallyDrop::new(res.into_boxed_slice()); + SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), slice.len()))) + } + } + } +} + +basic_op!(BitXor, SmallUint, bitxor); diff --git a/src/ops.rs b/src/ops.rs index bba35bd..7cef35e 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -430,6 +430,7 @@ fn mul(a: &SmallUint, b: &SmallUint) -> SmallUint { }, + (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => { let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; diff --git a/src/tests.rs b/src/tests.rs index 7e4818b..e75196d 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -93,6 +93,67 @@ fn test_op_sub_u_u() { } +#[test] +#[cfg(feature = "num-bigint")] +fn test_op_and_u_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]) & 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_or_u_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])); + +} + +#[test] +#[cfg(feature = "num-bigint")] +fn test_op_xor_u_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])); + +} + + #[test] #[cfg(feature = "num-bigint")] fn test_bigint() {