diff --git a/src/bigint/bits.rs b/src/bigint/bits.rs index 686def4d..3aa2c1c0 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::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}; +use num_traits::{Signed, ToPrimitive, Zero}; // Negation in two's complement. // acc must be initialized as 1 for least-significant digit. @@ -529,3 +530,1067 @@ 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.sign = Plus; + 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.sign = Plus; + 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.sign = Plus; + 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.sign = Plus; + 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.sign = Plus; + self.normalize(); + } + (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(); + } + } + } +} + +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.sign = Plus; + self.normalize(); + } + (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(); + } + } + } +} + +#[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.sign = Plus; + self.normalize(); + } + (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(); + } + } + } +} + +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.sign = Plus; + self.normalize(); + } + (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(); + } + } + } +} + +#[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.sign = Plus; + self.normalize(); + } + (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(); + } + } + } +} + +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.sign = Minus; + 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.sign = Minus; + 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.sign = Minus; + 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.sign = Minus; + 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.sign = Minus; + self.normalize(); + } + } + } +} + +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.sign = Plus; + 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.sign = Minus; + 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.sign = Plus; + 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.sign = Minus; + 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.sign = Plus; + 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.sign = Minus; + 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.sign = Plus; + 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.sign = Minus; + 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.sign = Plus; + 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.sign = Minus; + self.normalize(); + } + } + } +} diff --git a/src/biguint/bits.rs b/src/biguint/bits.rs index 58c755a6..fcb57ae4 100644 --- a/src/biguint/bits.rs +++ b/src/biguint/bits.rs @@ -1,6 +1,13 @@ use super::{BigUint, IntDigits}; +use crate::big_digit::{self, BigDigit}; +use crate::UsizePromotion; + +#[cfg(not(u64_digit))] +use crate::std_alloc::Vec; + 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 +98,369 @@ impl<'a> BitXorAssign<&'a BigUint> for BigUint { self.normalize(); } } + +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); + +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: 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(); + } + } +} + +#[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 = 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; + } + } + } +} + +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; + } + } + } +} diff --git a/tests/bigint_bitwise.rs b/tests/bigint_bitwise.rs index 6c1e82fe..51c81d49 100644 --- a/tests/bigint_bitwise.rs +++ b/tests/bigint_bitwise.rs @@ -176,3 +176,36 @@ 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() + ); + } + } +}