From cc58b6d958fe5d64b163cdf5a64afe6adf14f103 Mon Sep 17 00:00:00 2001 From: Patrick Norton Date: Sat, 7 Aug 2021 19:19:12 -0400 Subject: [PATCH 01/11] Added bitwise and operations on primitives --- src/biguint/bits.rs | 227 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) diff --git a/src/biguint/bits.rs b/src/biguint/bits.rs index 58c755a6..cb30e00c 100644 --- a/src/biguint/bits.rs +++ b/src/biguint/bits.rs @@ -1,6 +1,10 @@ use super::{BigUint, IntDigits}; +use crate::big_digit::{self, BigDigit}; +use crate::{IsizePromotion, UsizePromotion}; + use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign}; +use num_traits::Zero; forward_val_val_binop!(impl BitAnd for BigUint, bitand); forward_ref_val_binop!(impl BitAnd for BigUint, bitand); @@ -91,3 +95,226 @@ impl<'a> BitXorAssign<&'a BigUint> for BigUint { self.normalize(); } } + +promote_all_scalars!(impl BitAnd for BigUint, bitand); +promote_all_scalars_assign!(impl BitAndAssign for BigUint, bitand_assign); +forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigUint, bitand); +forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigUint, bitand); +forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigUint, bitand); + +impl BitAnd for BigUint { + type Output = BigUint; + + fn bitand(mut self, rhs: u32) -> Self::Output { + self &= rhs; + self + } +} + +impl BitAndAssign for BigUint { + fn bitand_assign(&mut self, rhs: u32) { + if !self.is_zero() { + self.data[0] &= rhs as BigDigit; + self.data.drain(1..); + } + } +} + +impl BitAnd for BigUint { + type Output = BigUint; + + fn bitand(mut self, rhs: u64) -> Self::Output { + self &= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitAndAssign for BigUint { + fn bitand_assign(&mut self, rhs: u64) { + if !self.is_zero() { + self.data[0] &= rhs as BigDigit; + self.data.drain(1..); + } + } +} + +#[cfg(not(u64_digit))] +impl BitAndAssign for BigUint { + fn bitand_assign(&mut self, rhs: u64) { + if !self.is_zero() { + self.data[0] &= rhs as BigDigit; + if self.data.len() > 1 { + self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; + self.data.drain(2..); + } + } + } +} + +impl BitAnd for BigUint { + type Output = BigUint; + + fn bitand(mut self, rhs: u128) -> Self::Output { + self &= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitAndAssign for BigUint { + fn bitand_assign(&mut self, rhs: u128) { + if !self.is_zero() { + self.data[0] &= rhs as BigDigit; + if self.data.len() > 1 { + self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; + self.data.drain(2..); + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitAndAssign for BigUint { + fn bitand_assign(&mut self, rhs: u128) { + match self.data.len() { + 0 => {} + 1 => self.data[0] &= rhs as BigDigit, + 2 => { + self.data[0] &= rhs as BigDigit; + self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; + } + 3 => { + self.data[0] &= rhs as BigDigit; + self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; + self.data[2] &= (rhs >> (big_digit::BITS * 2)) as BigDigit; + } + _ => { + self.data[0] &= rhs as BigDigit; + self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; + self.data[2] &= (rhs >> (big_digit::BITS * 2)) as BigDigit; + self.data[3] &= (rhs >> (big_digit::BITS * 3)) as BigDigit; + self.data.drain(4..); + } + } + } +} + +// Implementation note: The signed bitwise variants work because `i* as u*` +// produces numbers with identical bit patterns, thus bitwise operations will +// return identical results. The only semantic difference lies in the leading +// zeroes, which (conceptually) are all 0 if positive, and all one when +// negative. As such, this will only truncate the leading bits when positive, +// since x & 0 == 0. + +forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigUint, bitand); +forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigUint, bitand); +forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigUint, bitand); + +impl BitAnd for BigUint { + type Output = BigUint; + + fn bitand(mut self, rhs: i32) -> Self::Output { + self &= rhs; + self + } +} + +impl BitAndAssign for BigUint { + fn bitand_assign(&mut self, rhs: i32) { + if !self.is_zero() { + self.data[0] &= rhs as BigDigit; + if rhs >= 0 { + self.data.drain(1..); + } + } + } +} + +impl BitAnd for BigUint { + type Output = BigUint; + + fn bitand(mut self, rhs: i64) -> Self::Output { + self &= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitAndAssign for BigUint { + fn bitand_assign(&mut self, rhs: i64) { + if !self.is_zero() { + self.data[0] &= rhs as BigDigit; + if rhs >= 0 { + self.data.drain(1..); + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitAndAssign for BigUint { + fn bitand_assign(&mut self, rhs: i64) { + if !self.is_zero() { + self.data[0] &= rhs as BigDigit; + if self.data.len() > 1 { + self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; + if rhs >= 0 { + self.data.drain(2..); + } + } + } + } +} + +impl BitAnd for BigUint { + type Output = BigUint; + + fn bitand(mut self, rhs: i128) -> Self::Output { + self &= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitAndAssign for BigUint { + fn bitand_assign(&mut self, rhs: i128) { + if !self.is_zero() { + self.data[0] &= rhs as BigDigit; + if self.data.len() > 1 { + self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; + if rhs >= 0 { + self.data.drain(2..); + } + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitAndAssign for BigUint { + fn bitand_assign(&mut self, rhs: i128) { + match self.data.len() { + 0 => {} + 1 => self.data[0] &= rhs as BigDigit, + 2 => { + self.data[0] &= rhs as BigDigit; + self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; + } + 3 => { + self.data[0] &= rhs as BigDigit; + self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; + self.data[2] &= (rhs >> (big_digit::BITS * 2)) as BigDigit; + } + _ => { + self.data[0] &= rhs as BigDigit; + self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; + self.data[2] &= (rhs >> (big_digit::BITS * 2)) as BigDigit; + self.data[3] &= (rhs >> (big_digit::BITS * 3)) as BigDigit; + if rhs >= 0 { + self.data.drain(4..); + } + } + } + } +} From 4b1db1064cc761c580df5e87983df6aafd12ae26 Mon Sep 17 00:00:00 2001 From: Patrick Norton Date: Sat, 7 Aug 2021 20:39:29 -0400 Subject: [PATCH 02/11] Added bitwise or operations on primitives --- src/biguint/bits.rs | 127 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/src/biguint/bits.rs b/src/biguint/bits.rs index cb30e00c..1e79a097 100644 --- a/src/biguint/bits.rs +++ b/src/biguint/bits.rs @@ -318,3 +318,130 @@ impl BitAndAssign for BigUint { } } } + +// Implementation note: Bitwise or (and xor) are not implemented for signed +// types because there is no reasonable value for the result to be if rhs is +// negative. + +promote_unsigned_scalars!(impl BitOr for BigUint, bitor); +promote_unsigned_scalars_assign!(impl BitOrAssign for BigUint, bitor_assign); +forward_all_scalar_binop_to_val_val_commutative!(impl BitOr for BigUint, bitor); +forward_all_scalar_binop_to_val_val_commutative!(impl BitOr for BigUint, bitor); +forward_all_scalar_binop_to_val_val_commutative!(impl BitOr for BigUint, bitor); + +impl BitOr for BigUint { + type Output = BigUint; + + fn bitor(mut self, rhs: u32) -> Self::Output { + self |= rhs; + self + } +} + +impl BitOrAssign for BigUint { + fn bitor_assign(&mut self, rhs: u32) { + if !self.is_zero() { + self.data[0] |= rhs as BigDigit; + } else { + *self = rhs.into(); + } + } +} + +impl BitOr for BigUint { + type Output = BigUint; + + fn bitor(mut self, rhs: u64) -> Self::Output { + self |= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitOrAssign for BigUint { + fn bitor_assign(&mut self, rhs: u64) { + if !self.is_zero() { + self.data[0] |= rhs; + } else { + self.data.push(rhs); + } + } +} + +#[cfg(not(u64_digit))] +impl BitOrAssign for BigUint { + fn bitor_assign(&mut self, rhs: u64) { + match self.data.len() { + 0 => *self = rhs.into(), + 1 => { + self.data[0] |= rhs as BigDigit; + if rhs > big_digit::MAX { + self.data.push((rhs >> big_digit::BITS) as BigDigit); + } + } + _ => { + self.data[0] |= rhs as BigDigit; + self.data[1] |= (rhs >> big_digit::BITS) as u32; + } + } + } +} + +impl BitOr for BigUint { + type Output = BigUint; + + fn bitor(mut self, rhs: u128) -> Self::Output { + self |= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitOrAssign for BigUint { + fn bitor_assign(&mut self, rhs: u128) { + if !self.is_zero() { + self.data[0] |= rhs as BigDigit; + if self.data.len() > 1 { + self.data[1] |= (rhs >> big_digit::BITS) as BigDigit; + } else if rhs > big_digit::MAX as u128 { + self.data.push((rhs >> big_digit::BITS) as BigDigit); + } + } else { + *self = rhs.into(); + } + } +} + +#[cfg(not(u64_digit))] +impl BitOrAssign for BigUint { + fn bitor_assign(&mut self, rhs: u128) { + let [a, b, c, d] = rhs.into(); + match self.data.len() { + 0 => *self = rhs.into(), + 1 => { + self.data[0] &= rhs as BigDigit; + self.data.push( (rhs >> big_digit::BITS) as BigDigit); + self.data.push( (rhs >> (big_digit::BITS * 2)) as BigDigit); + self.data.push( (rhs >> (big_digit::BITS * 3)) as BigDigit); + } + 2 => { + self.data[0] &= rhs as BigDigit; + self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; + self.data.push( (rhs >> (big_digit::BITS * 2)) as BigDigit); + self.data.push( (rhs >> (big_digit::BITS * 3)) as BigDigit); + } + 3 => { + self.data[0] &= rhs as BigDigit; + self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; + self.data[2] &= (rhs >> (big_digit::BITS * 2)) as BigDigit; + self.data.push( (rhs >> (big_digit::BITS * 3)) as BigDigit); + } + _ => { + self.data[0] &= rhs as BigDigit; + self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; + self.data[2] &= (rhs >> (big_digit::BITS * 2)) as BigDigit; + self.data[3] &= (rhs >> (big_digit::BITS * 3)) as BigDigit; + } + } + } +} From 87bd2610ae5cd8c3d3db9cca4bb0fa63e95421f6 Mon Sep 17 00:00:00 2001 From: Patrick Norton Date: Sat, 7 Aug 2021 20:49:59 -0400 Subject: [PATCH 03/11] Prevented extra pushes of leading zeroes --- src/biguint/bits.rs | 49 +++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/src/biguint/bits.rs b/src/biguint/bits.rs index 1e79a097..da26626e 100644 --- a/src/biguint/bits.rs +++ b/src/biguint/bits.rs @@ -3,6 +3,9 @@ use super::{BigUint, IntDigits}; use crate::big_digit::{self, BigDigit}; use crate::{IsizePromotion, UsizePromotion}; +#[cfg(not(u64_digit))] +use crate::std_alloc::Vec; + use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign}; use num_traits::Zero; @@ -412,35 +415,47 @@ impl BitOrAssign for BigUint { } } +#[inline] +#[cfg(not(u64_digit))] +fn push_nonzero(data: &mut Vec, to_add: &[T]) { + for i in to_add { + if i.is_zero() { + return; + } else { + data.push(*i); + } + } +} + #[cfg(not(u64_digit))] impl BitOrAssign for BigUint { fn bitor_assign(&mut self, rhs: u128) { - let [a, b, c, d] = rhs.into(); + let a = rhs as BigDigit; + let b = (rhs >> big_digit::BITS) as BigDigit; + let c = (rhs >> (big_digit::BITS * 2)) as BigDigit; + let d = (rhs >> (big_digit::BITS * 2)) as BigDigit; match self.data.len() { 0 => *self = rhs.into(), 1 => { - self.data[0] &= rhs as BigDigit; - self.data.push( (rhs >> big_digit::BITS) as BigDigit); - self.data.push( (rhs >> (big_digit::BITS * 2)) as BigDigit); - self.data.push( (rhs >> (big_digit::BITS * 3)) as BigDigit); + self.data[0] &= a; + push_nonzero(&mut self.data, &[b, c, d]); } 2 => { - self.data[0] &= rhs as BigDigit; - self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; - self.data.push( (rhs >> (big_digit::BITS * 2)) as BigDigit); - self.data.push( (rhs >> (big_digit::BITS * 3)) as BigDigit); + self.data[0] &= a; + self.data[1] &= b; + push_nonzero(&mut self.data, &[c, d]); } 3 => { - self.data[0] &= rhs as BigDigit; - self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; - self.data[2] &= (rhs >> (big_digit::BITS * 2)) as BigDigit; - self.data.push( (rhs >> (big_digit::BITS * 3)) as BigDigit); + self.data[0] &= a; + self.data[1] &= b; + self.data[2] &= c; + push_nonzero(&mut self.data, &[d]); } _ => { - self.data[0] &= rhs as BigDigit; - self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; - self.data[2] &= (rhs >> (big_digit::BITS * 2)) as BigDigit; - self.data[3] &= (rhs >> (big_digit::BITS * 3)) as BigDigit; + self.data[0] &= a; + self.data[1] &= b; + self.data[2] &= c; + self.data[3] &= d; } } } From 6e8c48b7eb1182fb916925c11cf54d8a2c110794 Mon Sep 17 00:00:00 2001 From: Patrick Norton Date: Sun, 8 Aug 2021 06:23:36 -0400 Subject: [PATCH 04/11] Added bitwise xor operations on primitives --- src/biguint/bits.rs | 123 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/src/biguint/bits.rs b/src/biguint/bits.rs index da26626e..3cc17a68 100644 --- a/src/biguint/bits.rs +++ b/src/biguint/bits.rs @@ -460,3 +460,126 @@ impl BitOrAssign for BigUint { } } } + +promote_unsigned_scalars!(impl BitXor for BigUint, bitxor); +promote_unsigned_scalars_assign!(impl BitXorAssign for BigUint, bitxor_assign); +forward_all_scalar_binop_to_val_val_commutative!(impl BitXor for BigUint, bitxor); +forward_all_scalar_binop_to_val_val_commutative!(impl BitXor for BigUint, bitxor); +forward_all_scalar_binop_to_val_val_commutative!(impl BitXor for BigUint, bitxor); + +impl BitXor for BigUint { + type Output = BigUint; + + fn bitxor(mut self, rhs: u32) -> Self::Output { + self ^= rhs; + self + } +} + +impl BitXorAssign for BigUint { + fn bitxor_assign(&mut self, rhs: u32) { + if !self.is_zero() { + self.data[0] ^= rhs as BigDigit; + } else { + *self = rhs.into(); + } + } +} + +impl BitXor for BigUint { + type Output = BigUint; + + fn bitxor(mut self, rhs: u64) -> Self::Output { + self ^= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitXorAssign for BigUint { + fn bitxor_assign(&mut self, rhs: u64) { + if !self.is_zero() { + self.data[0] ^= rhs; + } else { + self.data.push(rhs); + } + } +} + +#[cfg(not(u64_digit))] +impl BitXorAssign for BigUint { + fn bitxor_assign(&mut self, rhs: u64) { + match self.data.len() { + 0 => *self = rhs.into(), + 1 => { + self.data[0] ^= rhs as BigDigit; + if rhs > big_digit::MAX { + self.data.push((rhs >> big_digit::BITS) as BigDigit); + } + } + _ => { + self.data[0] ^= rhs as BigDigit; + self.data[1] ^= (rhs >> big_digit::BITS) as u32; + } + } + } +} + +impl BitXor for BigUint { + type Output = BigUint; + + fn bitxor(mut self, rhs: u128) -> Self::Output { + self ^= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitXorAssign for BigUint { + fn bitxor_assign(&mut self, rhs: u128) { + if !self.is_zero() { + self.data[0] ^= rhs as BigDigit; + if self.data.len() > 1 { + self.data[1] ^= (rhs >> big_digit::BITS) as BigDigit; + } else if rhs > big_digit::MAX as u128 { + self.data.push((rhs >> big_digit::BITS) as BigDigit); + } + } else { + *self = rhs.into(); + } + } +} + +#[cfg(not(u64_digit))] +impl BitXorAssign for BigUint { + fn bitxor_assign(&mut self, rhs: u128) { + let a = rhs as BigDigit; + let b = (rhs >> big_digit::BITS) as BigDigit; + let c = (rhs >> (big_digit::BITS * 2)) as BigDigit; + let d = (rhs >> (big_digit::BITS * 2)) as BigDigit; + match self.data.len() { + 0 => *self = rhs.into(), + 1 => { + self.data[0] ^= a; + push_nonzero(&mut self.data, &[b, c, d]); + } + 2 => { + self.data[0] ^= a; + self.data[1] ^= b; + push_nonzero(&mut self.data, &[c, d]); + } + 3 => { + self.data[0] ^= a; + self.data[1] ^= b; + self.data[2] ^= c; + push_nonzero(&mut self.data, &[d]); + } + _ => { + self.data[0] ^= a; + self.data[1] ^= b; + self.data[2] ^= c; + self.data[3] ^= d; + } + } + } +} From 04bac921fd913301661d451784aa7590ae7f15ac Mon Sep 17 00:00:00 2001 From: Patrick Norton Date: Sun, 8 Aug 2021 07:56:50 -0400 Subject: [PATCH 05/11] Added bitwise and to BigInt --- src/bigint/bits.rs | 320 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 318 insertions(+), 2 deletions(-) diff --git a/src/bigint/bits.rs b/src/bigint/bits.rs index 686def4d..c44801f5 100644 --- a/src/bigint/bits.rs +++ b/src/bigint/bits.rs @@ -1,13 +1,14 @@ use super::BigInt; -use super::Sign::{Minus, NoSign, Plus}; +use super::Sign::{self, Minus, NoSign, Plus}; +use crate::{IsizePromotion, UsizePromotion}; use crate::big_digit::{self, BigDigit, DoubleBigDigit}; use crate::biguint::IntDigits; use crate::std_alloc::Vec; use core::cmp::Ordering::{Equal, Greater, Less}; use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign}; -use num_traits::{ToPrimitive, Zero}; +use num_traits::{ToPrimitive, Zero, Signed}; // Negation in two's complement. // acc must be initialized as 1 for least-significant digit. @@ -529,3 +530,318 @@ pub(super) fn set_negative_bit(x: &mut BigInt, bit: u64, value: bool) { } } } + +promote_all_scalars!(impl BitAnd for BigInt, bitand); +promote_all_scalars_assign!(impl BitAndAssign for BigInt, bitand_assign); +forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigInt, bitand); +forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigInt, bitand); +forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigInt, bitand); + +impl BitAnd for BigInt { + type Output = BigInt; + + fn bitand(mut self, rhs: u32) -> Self::Output { + self &= rhs; + self + } +} + +impl BitAndAssign for BigInt { + fn bitand_assign(&mut self, rhs: u32) { + match self.sign { + Minus => { + bitand_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.normalize(); + } + NoSign => self.set_zero(), + Plus => { + self.data &= rhs; + self.normalize(); + } + } + } +} + +impl BitAnd for BigInt { + type Output = BigInt; + + fn bitand(mut self, rhs: u64) -> Self::Output { + self &= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitAndAssign for BigInt { + fn bitand_assign(&mut self, rhs: u64) { + match self.sign { + Minus => { + bitand_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.normalize(); + } + NoSign => self.set_zero(), + Plus => { + self.data &= rhs; + self.normalize(); + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitAndAssign for BigInt { + fn bitand_assign(&mut self, rhs: u64) { + match self.sign { + Minus => { + bitand_neg_pos( + self.digits_mut(), + &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + NoSign => self.set_zero(), + Plus => { + self.data &= rhs; + self.normalize(); + } + } + } +} + +impl BitAnd for BigInt { + type Output = BigInt; + + fn bitand(mut self, rhs: u128) -> Self::Output { + self &= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitAndAssign for BigInt { + fn bitand_assign(&mut self, rhs: u128) { + match self.sign { + Minus => { + bitand_neg_pos( + self.digits_mut(), + &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + NoSign => self.set_zero(), + Plus => { + self.data &= rhs; + self.normalize(); + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitAndAssign for BigInt { + fn bitand_assign(&mut self, rhs: u128) { + match self.sign { + Minus => { + bitand_neg_pos( + self.digits_mut(), + &[ + rhs as BigDigit, + (rhs >> big_digit::BITS) as BigDigit, + (rhs >> (big_digit::BITS * 2)) as BigDigit, + (rhs >> (big_digit::BITS * 3)) as BigDigit, + ], + ); + self.normalize(); + } + NoSign => self.set_zero(), + Plus => { + self.data &= rhs; + self.normalize(); + } + } + } +} + +#[inline] +fn get_sign(x: &T) -> Sign { + if x.is_positive() { + Sign::Plus + } else if x.is_negative() { + Sign::Minus + } else { + Sign::NoSign + } +} + +forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigInt, bitand); +forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigInt, bitand); +forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigInt, bitand); + +impl BitAnd for BigInt { + type Output = BigInt; + + fn bitand(mut self, rhs: i32) -> Self::Output { + self &= rhs; + self + } +} + +impl BitAndAssign for BigInt { + fn bitand_assign(&mut self, rhs: i32) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => self.set_zero(), + (_, NoSign) => self.set_zero(), + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u32; + bitand_neg_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.normalize(); + }, + (Minus, Plus) => { + bitand_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.normalize(); + } + (Plus, _) => { + self.data &= rhs; + self.normalize(); + } + } + } +} + +impl BitAnd for BigInt { + type Output = BigInt; + + fn bitand(mut self, rhs: i64) -> Self::Output { + self &= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitAndAssign for BigInt { + fn bitand_assign(&mut self, rhs: i64) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => self.set_zero(), + (_, NoSign) => self.set_zero(), + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u64; + bitand_neg_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.normalize(); + }, + (Minus, Plus) => { + bitand_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.normalize(); + } + (Plus, _) => { + self.data &= rhs; + self.normalize(); + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitAndAssign for BigInt { + fn bitand_assign(&mut self, rhs: i64) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => self.set_zero(), + (_, NoSign) => self.set_zero(), + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u64; + bitand_neg_neg( + self.digits_mut(), + &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + }, + (Minus, Plus) => { + bitand_neg_pos( + self.digits_mut(), + &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + (Plus, _) => { + self.data &= rhs; + self.normalize(); + } + } + } +} + +impl BitAnd for BigInt { + type Output = BigInt; + + fn bitand(mut self, rhs: i128) -> Self::Output { + self &= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitAndAssign for BigInt { + fn bitand_assign(&mut self, rhs: i128) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => self.set_zero(), + (_, NoSign) => self.set_zero(), + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u128; + bitand_neg_neg( + self.digits_mut(), + &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + }, + (Minus, Plus) => { + bitand_neg_pos( + self.digits_mut(), + &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + (Plus, _) => { + self.data &= rhs; + self.normalize(); + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitAndAssign for BigInt { + fn bitand_assign(&mut self, rhs: i128) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => self.set_zero(), + (_, NoSign) => self.set_zero(), + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u128; + bitand_neg_neg( + self.digits_mut(), + &[ + rhs as BigDigit, + (rhs >> big_digit::BITS) as BigDigit, + (rhs >> (big_digit::BITS * 2)) as BigDigit, + (rhs >> (big_digit::BITS * 3)) as BigDigit, + ], + ); + self.normalize(); + }, + (Minus, Plus) => { + bitand_neg_pos( + self.digits_mut(), + &[ + rhs as BigDigit, + (rhs >> big_digit::BITS) as BigDigit, + (rhs >> (big_digit::BITS * 2)) as BigDigit, + (rhs >> (big_digit::BITS * 3)) as BigDigit, + ], + ); + self.normalize(); + } + (Plus, _) => { + self.data &= rhs; + self.normalize(); + } + } + } +} From f1dd2635a4cf41f4ae92ad081f475142095078d3 Mon Sep 17 00:00:00 2001 From: Patrick Norton Date: Sun, 8 Aug 2021 08:14:51 -0400 Subject: [PATCH 06/11] Added bitwise or to BigInt --- src/bigint/bits.rs | 343 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) diff --git a/src/bigint/bits.rs b/src/bigint/bits.rs index c44801f5..9473ee8d 100644 --- a/src/bigint/bits.rs +++ b/src/bigint/bits.rs @@ -845,3 +845,346 @@ impl BitAndAssign for BigInt { } } } + +promote_unsigned_scalars!(impl BitOr for BigInt, bitor); +promote_unsigned_scalars_assign!(impl BitOrAssign for BigInt, bitor_assign); +forward_all_scalar_binop_to_val_val_commutative!(impl BitOr for BigInt, bitor); +forward_all_scalar_binop_to_val_val_commutative!(impl BitOr for BigInt, bitor); +forward_all_scalar_binop_to_val_val_commutative!(impl BitOr for BigInt, bitor); + +impl BitOr for BigInt { + type Output = BigInt; + + fn bitor(mut self, rhs: u32) -> Self::Output { + self |= rhs; + self + } +} + +impl BitOrAssign for BigInt { + fn bitor_assign(&mut self, rhs: u32) { + match self.sign { + Minus => { + bitor_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.normalize(); + } + NoSign => *self = rhs.into(), + Plus => { + self.data |= rhs; + self.normalize(); + } + } + } +} + +impl BitOr for BigInt { + type Output = BigInt; + + fn bitor(mut self, rhs: u64) -> Self::Output { + self |= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitOrAssign for BigInt { + fn bitor_assign(&mut self, rhs: u64) { + match self.sign { + Minus => { + bitor_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.normalize(); + } + NoSign => *self = rhs.into(), + Plus => { + self.data |= rhs; + self.normalize(); + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitOrAssign for BigInt { + fn bitor_assign(&mut self, rhs: u64) { + match self.sign { + Minus => { + bitor_neg_pos( + self.digits_mut(), + &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + NoSign => *self = rhs.into(), + Plus => { + self.data |= rhs; + self.normalize(); + } + } + } +} + +impl BitOr for BigInt { + type Output = BigInt; + + fn bitor(mut self, rhs: u128) -> Self::Output { + self |= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitOrAssign for BigInt { + fn bitor_assign(&mut self, rhs: u128) { + match self.sign { + Minus => { + bitor_neg_pos( + self.digits_mut(), + &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + NoSign => *self = rhs.into(), + Plus => { + self.data |= rhs; + self.normalize(); + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitOrAssign for BigInt { + fn bitor_assign(&mut self, rhs: u128) { + match self.sign { + Minus => { + bitor_neg_pos( + self.digits_mut(), + &[ + rhs as BigDigit, + (rhs >> big_digit::BITS) as BigDigit, + (rhs >> (big_digit::BITS * 2)) as BigDigit, + (rhs >> (big_digit::BITS * 3)) as BigDigit, + ], + ); + self.normalize(); + } + NoSign => *self = rhs.into(), + Plus => { + self.data |= rhs; + self.normalize(); + } + } + } +} + +forward_all_scalar_binop_to_val_val_commutative!(impl BitOr for BigInt, bitor); +forward_all_scalar_binop_to_val_val_commutative!(impl BitOr for BigInt, bitor); +forward_all_scalar_binop_to_val_val_commutative!(impl BitOr for BigInt, bitor); + +impl BitOr for BigInt { + type Output = BigInt; + + fn bitor(mut self, rhs: i32) -> Self::Output { + self &= rhs; + self + } +} + +impl BitOrAssign for BigInt { + fn bitor_assign(&mut self, rhs: i32) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => *self = rhs.into(), + (_, NoSign) => {} + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u32; + bitor_neg_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.normalize(); + }, + (Minus, Plus) => { + bitor_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.normalize(); + } + (Plus, Plus) => { + self.data |= rhs as u32; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u32; + bitor_pos_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.normalize(); + } + } + } +} + +impl BitOr for BigInt { + type Output = BigInt; + + fn bitor(mut self, rhs: i64) -> Self::Output { + self |= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitOrAssign for BigInt { + fn bitor_assign(&mut self, rhs: i64) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => *self = rhs.into(), + (_, NoSign) => {} + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u64; + bitor_neg_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.normalize(); + }, + (Minus, Plus) => { + bitor_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.normalize(); + } + (Plus, Plus) => { + self.data |= rhs as u64; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u64; + bitor_pos_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.normalize(); + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitOrAssign for BigInt { + fn bitor_assign(&mut self, rhs: i64) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => *self = rhs.into(), + (_, NoSign) => {} + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u64; + bitor_neg_neg( + self.digits_mut(), + &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + }, + (Minus, Plus) => { + bitor_neg_pos( + self.digits_mut(), + &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + (Plus, Plus) => { + self.data |= rhs as u64; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u64; + bitor_pos_neg( + self.digits_mut(), + &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + } + } +} + +impl BitOr for BigInt { + type Output = BigInt; + + fn bitor(mut self, rhs: i128) -> Self::Output { + self |= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitOrAssign for BigInt { + fn bitor_assign(&mut self, rhs: i128) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => *self = rhs.into(), + (_, NoSign) => {} + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u128; + bitor_neg_neg( + self.digits_mut(), + &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + }, + (Minus, Plus) => { + bitor_neg_pos( + self.digits_mut(), + &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + (Plus, Plus) => { + self.data |= rhs as u128; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u128; + bitor_pos_neg( + self.digits_mut(), + &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitOrAssign for BigInt { + fn bitor_assign(&mut self, rhs: i128) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => *self = rhs.into(), + (_, NoSign) => {} + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u128; + bitor_neg_neg( + self.digits_mut(), + &[ + rhs as BigDigit, + (rhs >> big_digit::BITS) as BigDigit, + (rhs >> (big_digit::BITS * 2)) as BigDigit, + (rhs >> (big_digit::BITS * 3)) as BigDigit, + ], + ); + self.normalize(); + }, + (Minus, Plus) => { + bitor_neg_pos( + self.digits_mut(), + &[ + rhs as BigDigit, + (rhs >> big_digit::BITS) as BigDigit, + (rhs >> (big_digit::BITS * 2)) as BigDigit, + (rhs >> (big_digit::BITS * 3)) as BigDigit, + ], + ); + self.normalize(); + } + (Plus, Plus) => { + self.data |= rhs as u128; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u128; + bitor_pos_neg( + self.digits_mut(), + &[ + rhs as BigDigit, + (rhs >> big_digit::BITS) as BigDigit, + (rhs >> (big_digit::BITS * 2)) as BigDigit, + (rhs >> (big_digit::BITS * 3)) as BigDigit, + ], + ); + self.normalize(); + } + } + } +} From 257cf19952f9d7797e3e725b60f1cee8a60ee62f Mon Sep 17 00:00:00 2001 From: Patrick Norton Date: Sun, 8 Aug 2021 08:53:16 -0400 Subject: [PATCH 07/11] Added bitwise xor to BigInt --- src/bigint/bits.rs | 343 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) diff --git a/src/bigint/bits.rs b/src/bigint/bits.rs index 9473ee8d..2ae4ab5a 100644 --- a/src/bigint/bits.rs +++ b/src/bigint/bits.rs @@ -1188,3 +1188,346 @@ impl BitOrAssign for BigInt { } } } + +promote_unsigned_scalars!(impl BitXor for BigInt, bitxor); +promote_unsigned_scalars_assign!(impl BitXorAssign for BigInt, bitxor_assign); +forward_all_scalar_binop_to_val_val_commutative!(impl BitXor for BigInt, bitxor); +forward_all_scalar_binop_to_val_val_commutative!(impl BitXor for BigInt, bitxor); +forward_all_scalar_binop_to_val_val_commutative!(impl BitXor for BigInt, bitxor); + +impl BitXor for BigInt { + type Output = BigInt; + + fn bitxor(mut self, rhs: u32) -> Self::Output { + self ^= rhs; + self + } +} + +impl BitXorAssign for BigInt { + fn bitxor_assign(&mut self, rhs: u32) { + match self.sign { + Minus => { + bitxor_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.normalize(); + } + NoSign => *self = rhs.into(), + Plus => { + self.data ^= rhs; + self.normalize(); + } + } + } +} + +impl BitXor for BigInt { + type Output = BigInt; + + fn bitxor(mut self, rhs: u64) -> Self::Output { + self ^= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitXorAssign for BigInt { + fn bitxor_assign(&mut self, rhs: u64) { + match self.sign { + Minus => { + bitxor_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.normalize(); + } + NoSign => *self = rhs.into(), + Plus => { + self.data ^= rhs; + self.normalize(); + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitXorAssign for BigInt { + fn bitxor_assign(&mut self, rhs: u64) { + match self.sign { + Minus => { + bitxor_neg_pos( + self.digits_mut(), + &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + NoSign => *self = rhs.into(), + Plus => { + self.data ^= rhs; + self.normalize(); + } + } + } +} + +impl BitXor for BigInt { + type Output = BigInt; + + fn bitxor(mut self, rhs: u128) -> Self::Output { + self ^= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitXorAssign for BigInt { + fn bitxor_assign(&mut self, rhs: u128) { + match self.sign { + Minus => { + bitxor_neg_pos( + self.digits_mut(), + &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + NoSign => *self = rhs.into(), + Plus => { + self.data ^= rhs; + self.normalize(); + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitXorAssign for BigInt { + fn bitxor_assign(&mut self, rhs: u128) { + match self.sign { + Minus => { + bitxor_neg_pos( + self.digits_mut(), + &[ + rhs as BigDigit, + (rhs >> big_digit::BITS) as BigDigit, + (rhs >> (big_digit::BITS * 2)) as BigDigit, + (rhs >> (big_digit::BITS * 3)) as BigDigit, + ], + ); + self.normalize(); + } + NoSign => *self = rhs.into(), + Plus => { + self.data ^= rhs; + self.normalize(); + } + } + } +} + +forward_all_scalar_binop_to_val_val_commutative!(impl BitXor for BigInt, bitxor); +forward_all_scalar_binop_to_val_val_commutative!(impl BitXor for BigInt, bitxor); +forward_all_scalar_binop_to_val_val_commutative!(impl BitXor for BigInt, bitxor); + +impl BitXor for BigInt { + type Output = BigInt; + + fn bitxor(mut self, rhs: i32) -> Self::Output { + self ^= rhs; + self + } +} + +impl BitXorAssign for BigInt { + fn bitxor_assign(&mut self, rhs: i32) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => *self = rhs.into(), + (_, NoSign) => {} + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u32; + bitxor_neg_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.normalize(); + }, + (Minus, Plus) => { + bitxor_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.normalize(); + } + (Plus, Plus) => { + self.data ^= rhs as u32; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u32; + bitxor_pos_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.normalize(); + } + } + } +} + +impl BitXor for BigInt { + type Output = BigInt; + + fn bitxor(mut self, rhs: i64) -> Self::Output { + self ^= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitXorAssign for BigInt { + fn bitxor_assign(&mut self, rhs: i64) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => *self = rhs.into(), + (_, NoSign) => {} + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u64; + bitxor_neg_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.normalize(); + }, + (Minus, Plus) => { + bitxor_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.normalize(); + } + (Plus, Plus) => { + self.data ^= rhs as u64; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u64; + bitxor_pos_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.normalize(); + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitXorAssign for BigInt { + fn bitxor_assign(&mut self, rhs: i64) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => *self = rhs.into(), + (_, NoSign) => {} + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u64; + bitxor_neg_neg( + self.digits_mut(), + &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + }, + (Minus, Plus) => { + bitxor_neg_pos( + self.digits_mut(), + &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + (Plus, Plus) => { + self.data ^= rhs as u64; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u64; + bitxor_pos_neg( + self.digits_mut(), + &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + } + } +} + +impl BitXor for BigInt { + type Output = BigInt; + + fn bitxor(mut self, rhs: i128) -> Self::Output { + self ^= rhs; + self + } +} + +#[cfg(u64_digit)] +impl BitXorAssign for BigInt { + fn bitxor_assign(&mut self, rhs: i128) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => *self = rhs.into(), + (_, NoSign) => {} + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u128; + bitxor_neg_neg( + self.digits_mut(), + &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + }, + (Minus, Plus) => { + bitxor_neg_pos( + self.digits_mut(), + &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + (Plus, Plus) => { + self.data ^= rhs as u128; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u128; + bitxor_pos_neg( + self.digits_mut(), + &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], + ); + self.normalize(); + } + } + } +} + +#[cfg(not(u64_digit))] +impl BitXorAssign for BigInt { + fn bitxor_assign(&mut self, rhs: i128) { + match (self.sign, get_sign(&rhs)) { + (NoSign, _) => *self = rhs.into(), + (_, NoSign) => {} + (Minus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u128; + bitxor_neg_neg( + self.digits_mut(), + &[ + rhs as BigDigit, + (rhs >> big_digit::BITS) as BigDigit, + (rhs >> (big_digit::BITS * 2)) as BigDigit, + (rhs >> (big_digit::BITS * 3)) as BigDigit, + ], + ); + self.normalize(); + }, + (Minus, Plus) => { + bitxor_neg_pos( + self.digits_mut(), + &[ + rhs as BigDigit, + (rhs >> big_digit::BITS) as BigDigit, + (rhs >> (big_digit::BITS * 2)) as BigDigit, + (rhs >> (big_digit::BITS * 3)) as BigDigit, + ], + ); + self.normalize(); + } + (Plus, Plus) => { + self.data ^= rhs as u128; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u128; + bitxor_pos_neg( + self.digits_mut(), + &[ + rhs as BigDigit, + (rhs >> big_digit::BITS) as BigDigit, + (rhs >> (big_digit::BITS * 2)) as BigDigit, + (rhs >> (big_digit::BITS * 3)) as BigDigit, + ], + ); + self.normalize(); + } + } + } +} From c2454390612375493e0e062290a95a2f4814037c Mon Sep 17 00:00:00 2001 From: Patrick Norton Date: Sun, 8 Aug 2021 09:11:46 -0400 Subject: [PATCH 08/11] Fixed sign issues --- src/bigint/bits.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/bigint/bits.rs b/src/bigint/bits.rs index 2ae4ab5a..7883ee76 100644 --- a/src/bigint/bits.rs +++ b/src/bigint/bits.rs @@ -577,6 +577,7 @@ impl BitAndAssign for BigInt { match self.sign { Minus => { bitand_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.sign = Plus; self.normalize(); } NoSign => self.set_zero(), @@ -597,6 +598,7 @@ impl BitAndAssign for BigInt { self.digits_mut(), &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], ); + self.sign = Plus; self.normalize(); } NoSign => self.set_zero(), @@ -626,6 +628,7 @@ impl BitAndAssign for BigInt { self.digits_mut(), &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], ); + self.sign = Plus; self.normalize(); } NoSign => self.set_zero(), @@ -651,6 +654,7 @@ impl BitAndAssign for BigInt { (rhs >> (big_digit::BITS * 3)) as BigDigit, ], ); + self.sign = Plus; self.normalize(); } NoSign => self.set_zero(), @@ -698,6 +702,7 @@ impl BitAndAssign for BigInt { }, (Minus, Plus) => { bitand_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.sign = Plus; self.normalize(); } (Plus, _) => { @@ -730,6 +735,7 @@ impl BitAndAssign for BigInt { }, (Minus, Plus) => { bitand_neg_pos(self.digits_mut(), &[rhs as BigDigit]); + self.sign = Plus; self.normalize(); } (Plus, _) => { @@ -759,6 +765,7 @@ impl BitAndAssign for BigInt { self.digits_mut(), &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], ); + self.sign = Plus; self.normalize(); } (Plus, _) => { @@ -797,6 +804,7 @@ impl BitAndAssign for BigInt { self.digits_mut(), &[rhs as BigDigit, (rhs >> big_digit::BITS) as BigDigit], ); + self.sign = Plus; self.normalize(); } (Plus, _) => { @@ -836,6 +844,7 @@ impl BitAndAssign for BigInt { (rhs >> (big_digit::BITS * 3)) as BigDigit, ], ); + self.sign = Plus; self.normalize(); } (Plus, _) => { @@ -1011,6 +1020,7 @@ impl BitOrAssign for BigInt { (Plus, Minus) => { let u_rhs = rhs.wrapping_abs() as u32; bitor_pos_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.sign = Minus; self.normalize(); } } @@ -1048,6 +1058,7 @@ impl BitOrAssign for BigInt { (Plus, Minus) => { let u_rhs = rhs.wrapping_abs() as u64; bitor_pos_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.sign = Minus; self.normalize(); } } @@ -1085,6 +1096,7 @@ impl BitOrAssign for BigInt { self.digits_mut(), &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], ); + self.sign = Minus; self.normalize(); } } @@ -1131,6 +1143,7 @@ impl BitOrAssign for BigInt { self.digits_mut(), &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], ); + self.sign = Minus; self.normalize(); } } @@ -1183,6 +1196,7 @@ impl BitOrAssign for BigInt { (rhs >> (big_digit::BITS * 3)) as BigDigit, ], ); + self.sign = Minus; self.normalize(); } } @@ -1341,6 +1355,7 @@ impl BitXorAssign for BigInt { (Minus, Minus) => { let u_rhs = rhs.wrapping_abs() as u32; bitxor_neg_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.sign = Plus; self.normalize(); }, (Minus, Plus) => { @@ -1354,6 +1369,7 @@ impl BitXorAssign for BigInt { (Plus, Minus) => { let u_rhs = rhs.wrapping_abs() as u32; bitxor_pos_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.sign = Minus; self.normalize(); } } @@ -1378,6 +1394,7 @@ impl BitXorAssign for BigInt { (Minus, Minus) => { let u_rhs = rhs.wrapping_abs() as u64; bitxor_neg_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.sign = Plus; self.normalize(); }, (Minus, Plus) => { @@ -1391,6 +1408,7 @@ impl BitXorAssign for BigInt { (Plus, Minus) => { let u_rhs = rhs.wrapping_abs() as u64; bitxor_pos_neg(self.digits_mut(), &[u_rhs as BigDigit]); + self.sign = Minus; self.normalize(); } } @@ -1409,6 +1427,7 @@ impl BitXorAssign for BigInt { self.digits_mut(), &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], ); + self.sign = Plus; self.normalize(); }, (Minus, Plus) => { @@ -1428,6 +1447,7 @@ impl BitXorAssign for BigInt { self.digits_mut(), &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], ); + self.sign = Minus; self.normalize(); } } @@ -1455,6 +1475,7 @@ impl BitXorAssign for BigInt { self.digits_mut(), &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], ); + self.sign = Plus; self.normalize(); }, (Minus, Plus) => { @@ -1474,6 +1495,7 @@ impl BitXorAssign for BigInt { self.digits_mut(), &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], ); + self.sign = Minus; self.normalize(); } } @@ -1497,6 +1519,7 @@ impl BitXorAssign for BigInt { (rhs >> (big_digit::BITS * 3)) as BigDigit, ], ); + self.sign = Plus; self.normalize(); }, (Minus, Plus) => { @@ -1526,6 +1549,7 @@ impl BitXorAssign for BigInt { (rhs >> (big_digit::BITS * 3)) as BigDigit, ], ); + self.sign = Minus; self.normalize(); } } From cac74d40e3bdad9266dbe7f7928182c6249d5513 Mon Sep 17 00:00:00 2001 From: Patrick Norton Date: Sun, 8 Aug 2021 09:12:00 -0400 Subject: [PATCH 09/11] Added bitwise tests --- tests/bigint_bitwise.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/bigint_bitwise.rs b/tests/bigint_bitwise.rs index 6c1e82fe..873605a6 100644 --- a/tests/bigint_bitwise.rs +++ b/tests/bigint_bitwise.rs @@ -176,3 +176,18 @@ fn test_bitwise_i64() { } } } + +#[test] +fn test_bitwise_primitive() { + for &prim_a in I64_VALUES.iter() { + let a = prim_a.to_bigint().unwrap(); + for &prim_b in I64_VALUES.iter() { + let and = (prim_a & prim_b).to_bigint().unwrap(); + let or = (prim_a | prim_b).to_bigint().unwrap(); + let xor = (prim_a ^ prim_b).to_bigint().unwrap(); + assert_eq!(a.clone() & prim_b, and, "{:x} & {:x}", a, prim_b.to_bigint().unwrap()); + assert_eq!(a.clone() | prim_b, or, "{:x} | {:x}", a, prim_b.to_bigint().unwrap()); + assert_eq!(a.clone() ^ prim_b, xor, "{:x} ^ {:x}", a, prim_b.to_bigint().unwrap()); + } + } +} From dded808e7b705b7c77407340c9be9012a52d547d Mon Sep 17 00:00:00 2001 From: Patrick Norton Date: Thu, 21 Oct 2021 16:21:55 -0700 Subject: [PATCH 10/11] Removed BitAnd for BigUint and signed primitives --- src/bigint/bits.rs | 95 +++++++++++++++++++++++---------- src/biguint/bits.rs | 125 ++------------------------------------------ 2 files changed, 70 insertions(+), 150 deletions(-) diff --git a/src/bigint/bits.rs b/src/bigint/bits.rs index 7883ee76..3aa2c1c0 100644 --- a/src/bigint/bits.rs +++ b/src/bigint/bits.rs @@ -1,14 +1,14 @@ use super::BigInt; use super::Sign::{self, Minus, NoSign, Plus}; -use crate::{IsizePromotion, UsizePromotion}; use crate::big_digit::{self, BigDigit, DoubleBigDigit}; use crate::biguint::IntDigits; use crate::std_alloc::Vec; +use crate::{IsizePromotion, UsizePromotion}; use core::cmp::Ordering::{Equal, Greater, Less}; use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign}; -use num_traits::{ToPrimitive, Zero, Signed}; +use num_traits::{Signed, ToPrimitive, Zero}; // Negation in two's complement. // acc must be initialized as 1 for least-significant digit. @@ -699,14 +699,19 @@ impl BitAndAssign for BigInt { let u_rhs = rhs.wrapping_abs() as u32; bitand_neg_neg(self.digits_mut(), &[u_rhs as BigDigit]); self.normalize(); - }, + } (Minus, Plus) => { bitand_neg_pos(self.digits_mut(), &[rhs as BigDigit]); self.sign = Plus; self.normalize(); } - (Plus, _) => { - self.data &= rhs; + (Plus, Plus) => { + self.data &= rhs as u32; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u32; + bitand_pos_neg(self.digits_mut(), &[u_rhs as BigDigit]); self.normalize(); } } @@ -732,14 +737,19 @@ impl BitAndAssign for BigInt { let u_rhs = rhs.wrapping_abs() as u64; bitand_neg_neg(self.digits_mut(), &[u_rhs as BigDigit]); self.normalize(); - }, + } (Minus, Plus) => { bitand_neg_pos(self.digits_mut(), &[rhs as BigDigit]); self.sign = Plus; self.normalize(); } - (Plus, _) => { - self.data &= rhs; + (Plus, Plus) => { + self.data &= rhs as u64; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u64; + bitand_pos_neg(self.digits_mut(), &[u_rhs as BigDigit]); self.normalize(); } } @@ -759,7 +769,7 @@ impl BitAndAssign for BigInt { &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], ); self.normalize(); - }, + } (Minus, Plus) => { bitand_neg_pos( self.digits_mut(), @@ -768,8 +778,16 @@ impl BitAndAssign for BigInt { self.sign = Plus; self.normalize(); } - (Plus, _) => { - self.data &= rhs; + (Plus, Plus) => { + self.data &= rhs as u128; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u64; + bitand_pos_neg( + self.digits_mut(), + &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], + ); self.normalize(); } } @@ -798,7 +816,7 @@ impl BitAndAssign for BigInt { &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], ); self.normalize(); - }, + } (Minus, Plus) => { bitand_neg_pos( self.digits_mut(), @@ -807,8 +825,16 @@ impl BitAndAssign for BigInt { self.sign = Plus; self.normalize(); } - (Plus, _) => { - self.data &= rhs; + (Plus, Plus) => { + self.data &= rhs as u128; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u128; + bitand_pos_neg( + self.digits_mut(), + &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], + ); self.normalize(); } } @@ -833,7 +859,7 @@ impl BitAndAssign for BigInt { ], ); self.normalize(); - }, + } (Minus, Plus) => { bitand_neg_pos( self.digits_mut(), @@ -847,8 +873,21 @@ impl BitAndAssign for BigInt { self.sign = Plus; self.normalize(); } - (Plus, _) => { - self.data &= rhs; + (Plus, Plus) => { + self.data &= rhs as u128; + self.normalize(); + } + (Plus, Minus) => { + let u_rhs = rhs.wrapping_abs() as u32; + bitand_pos_neg( + self.digits_mut(), + &[ + u_rhs as BigDigit, + (u_rhs >> big_digit::BITS) as BigDigit, + (u_rhs >> (big_digit::BITS * 2)) as BigDigit, + (u_rhs >> (big_digit::BITS * 3)) as BigDigit, + ], + ); self.normalize(); } } @@ -994,7 +1033,7 @@ impl BitOr for BigInt { type Output = BigInt; fn bitor(mut self, rhs: i32) -> Self::Output { - self &= rhs; + self |= rhs; self } } @@ -1008,7 +1047,7 @@ impl BitOrAssign for BigInt { let u_rhs = rhs.wrapping_abs() as u32; bitor_neg_neg(self.digits_mut(), &[u_rhs as BigDigit]); self.normalize(); - }, + } (Minus, Plus) => { bitor_neg_pos(self.digits_mut(), &[rhs as BigDigit]); self.normalize(); @@ -1046,7 +1085,7 @@ impl BitOrAssign for BigInt { let u_rhs = rhs.wrapping_abs() as u64; bitor_neg_neg(self.digits_mut(), &[u_rhs as BigDigit]); self.normalize(); - }, + } (Minus, Plus) => { bitor_neg_pos(self.digits_mut(), &[rhs as BigDigit]); self.normalize(); @@ -1078,7 +1117,7 @@ impl BitOrAssign for BigInt { &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], ); self.normalize(); - }, + } (Minus, Plus) => { bitor_neg_pos( self.digits_mut(), @@ -1125,7 +1164,7 @@ impl BitOrAssign for BigInt { &[u_rhs as BigDigit, (u_rhs >> big_digit::BITS) as BigDigit], ); self.normalize(); - }, + } (Minus, Plus) => { bitor_neg_pos( self.digits_mut(), @@ -1168,7 +1207,7 @@ impl BitOrAssign for BigInt { ], ); self.normalize(); - }, + } (Minus, Plus) => { bitor_neg_pos( self.digits_mut(), @@ -1357,7 +1396,7 @@ impl BitXorAssign for BigInt { bitxor_neg_neg(self.digits_mut(), &[u_rhs as BigDigit]); self.sign = Plus; self.normalize(); - }, + } (Minus, Plus) => { bitxor_neg_pos(self.digits_mut(), &[rhs as BigDigit]); self.normalize(); @@ -1396,7 +1435,7 @@ impl BitXorAssign for BigInt { bitxor_neg_neg(self.digits_mut(), &[u_rhs as BigDigit]); self.sign = Plus; self.normalize(); - }, + } (Minus, Plus) => { bitxor_neg_pos(self.digits_mut(), &[rhs as BigDigit]); self.normalize(); @@ -1429,7 +1468,7 @@ impl BitXorAssign for BigInt { ); self.sign = Plus; self.normalize(); - }, + } (Minus, Plus) => { bitxor_neg_pos( self.digits_mut(), @@ -1477,7 +1516,7 @@ impl BitXorAssign for BigInt { ); self.sign = Plus; self.normalize(); - }, + } (Minus, Plus) => { bitxor_neg_pos( self.digits_mut(), @@ -1521,7 +1560,7 @@ impl BitXorAssign for BigInt { ); self.sign = Plus; self.normalize(); - }, + } (Minus, Plus) => { bitxor_neg_pos( self.digits_mut(), diff --git a/src/biguint/bits.rs b/src/biguint/bits.rs index 3cc17a68..fcb57ae4 100644 --- a/src/biguint/bits.rs +++ b/src/biguint/bits.rs @@ -1,7 +1,7 @@ use super::{BigUint, IntDigits}; use crate::big_digit::{self, BigDigit}; -use crate::{IsizePromotion, UsizePromotion}; +use crate::UsizePromotion; #[cfg(not(u64_digit))] use crate::std_alloc::Vec; @@ -99,8 +99,8 @@ impl<'a> BitXorAssign<&'a BigUint> for BigUint { } } -promote_all_scalars!(impl BitAnd for BigUint, bitand); -promote_all_scalars_assign!(impl BitAndAssign for BigUint, bitand_assign); +promote_unsigned_scalars!(impl BitAnd for BigUint, bitand); +promote_unsigned_scalars_assign!(impl BitAndAssign for BigUint, bitand_assign); forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigUint, bitand); forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigUint, bitand); forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigUint, bitand); @@ -203,125 +203,6 @@ impl BitAndAssign for BigUint { } } -// Implementation note: The signed bitwise variants work because `i* as u*` -// produces numbers with identical bit patterns, thus bitwise operations will -// return identical results. The only semantic difference lies in the leading -// zeroes, which (conceptually) are all 0 if positive, and all one when -// negative. As such, this will only truncate the leading bits when positive, -// since x & 0 == 0. - -forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigUint, bitand); -forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigUint, bitand); -forward_all_scalar_binop_to_val_val_commutative!(impl BitAnd for BigUint, bitand); - -impl BitAnd for BigUint { - type Output = BigUint; - - fn bitand(mut self, rhs: i32) -> Self::Output { - self &= rhs; - self - } -} - -impl BitAndAssign for BigUint { - fn bitand_assign(&mut self, rhs: i32) { - if !self.is_zero() { - self.data[0] &= rhs as BigDigit; - if rhs >= 0 { - self.data.drain(1..); - } - } - } -} - -impl BitAnd for BigUint { - type Output = BigUint; - - fn bitand(mut self, rhs: i64) -> Self::Output { - self &= rhs; - self - } -} - -#[cfg(u64_digit)] -impl BitAndAssign for BigUint { - fn bitand_assign(&mut self, rhs: i64) { - if !self.is_zero() { - self.data[0] &= rhs as BigDigit; - if rhs >= 0 { - self.data.drain(1..); - } - } - } -} - -#[cfg(not(u64_digit))] -impl BitAndAssign for BigUint { - fn bitand_assign(&mut self, rhs: i64) { - if !self.is_zero() { - self.data[0] &= rhs as BigDigit; - if self.data.len() > 1 { - self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; - if rhs >= 0 { - self.data.drain(2..); - } - } - } - } -} - -impl BitAnd for BigUint { - type Output = BigUint; - - fn bitand(mut self, rhs: i128) -> Self::Output { - self &= rhs; - self - } -} - -#[cfg(u64_digit)] -impl BitAndAssign for BigUint { - fn bitand_assign(&mut self, rhs: i128) { - if !self.is_zero() { - self.data[0] &= rhs as BigDigit; - if self.data.len() > 1 { - self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; - if rhs >= 0 { - self.data.drain(2..); - } - } - } - } -} - -#[cfg(not(u64_digit))] -impl BitAndAssign for BigUint { - fn bitand_assign(&mut self, rhs: i128) { - match self.data.len() { - 0 => {} - 1 => self.data[0] &= rhs as BigDigit, - 2 => { - self.data[0] &= rhs as BigDigit; - self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; - } - 3 => { - self.data[0] &= rhs as BigDigit; - self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; - self.data[2] &= (rhs >> (big_digit::BITS * 2)) as BigDigit; - } - _ => { - self.data[0] &= rhs as BigDigit; - self.data[1] &= (rhs >> big_digit::BITS) as BigDigit; - self.data[2] &= (rhs >> (big_digit::BITS * 2)) as BigDigit; - self.data[3] &= (rhs >> (big_digit::BITS * 3)) as BigDigit; - if rhs >= 0 { - self.data.drain(4..); - } - } - } - } -} - // Implementation note: Bitwise or (and xor) are not implemented for signed // types because there is no reasonable value for the result to be if rhs is // negative. From c4d01aa2594ef8e8f9c42914e1e23c94df2bf187 Mon Sep 17 00:00:00 2001 From: Patrick Norton Date: Thu, 21 Oct 2021 16:25:23 -0700 Subject: [PATCH 11/11] Fixed formatting --- tests/bigint_bitwise.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/tests/bigint_bitwise.rs b/tests/bigint_bitwise.rs index 873605a6..51c81d49 100644 --- a/tests/bigint_bitwise.rs +++ b/tests/bigint_bitwise.rs @@ -185,9 +185,27 @@ fn test_bitwise_primitive() { let and = (prim_a & prim_b).to_bigint().unwrap(); let or = (prim_a | prim_b).to_bigint().unwrap(); let xor = (prim_a ^ prim_b).to_bigint().unwrap(); - assert_eq!(a.clone() & prim_b, and, "{:x} & {:x}", a, prim_b.to_bigint().unwrap()); - assert_eq!(a.clone() | prim_b, or, "{:x} | {:x}", a, prim_b.to_bigint().unwrap()); - assert_eq!(a.clone() ^ prim_b, xor, "{:x} ^ {:x}", a, prim_b.to_bigint().unwrap()); + assert_eq!( + a.clone() & prim_b, + and, + "{:x} & {:x}", + a, + prim_b.to_bigint().unwrap() + ); + assert_eq!( + a.clone() | prim_b, + or, + "{:x} | {:x}", + a, + prim_b.to_bigint().unwrap() + ); + assert_eq!( + a.clone() ^ prim_b, + xor, + "{:x} ^ {:x}", + a, + prim_b.to_bigint().unwrap() + ); } } }