diff --git a/src/bigint.rs b/src/bigint.rs index 8cd235a1..aa714eb2 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -1,8 +1,10 @@ use std::default::Default; -use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub, - BitAndAssign, BitOrAssign, BitXorAssign, Not}; +use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub, + AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, + MulAssign, RemAssign, ShlAssign, ShrAssign, SubAssign}; use std::str::{self, FromStr}; use std::fmt; +use std::mem; use std::cmp::Ordering::{self, Less, Greater, Equal}; use std::{i64, u64}; #[allow(unused_imports)] @@ -670,8 +672,9 @@ impl Shl for BigInt { type Output = BigInt; #[inline] - fn shl(self, rhs: usize) -> BigInt { - (&self) << rhs + fn shl(mut self, rhs: usize) -> BigInt { + self <<= rhs; + self } } @@ -684,6 +687,13 @@ impl<'a> Shl for &'a BigInt { } } +impl ShlAssign for BigInt { + #[inline] + fn shl_assign(&mut self, rhs: usize) { + self.data <<= rhs; + } +} + // Negative values need a rounding adjustment if there are any ones in the // bits that are getting shifted out. fn shr_round_down(i: &BigInt, rhs: usize) -> bool { @@ -697,10 +707,9 @@ impl Shr for BigInt { type Output = BigInt; #[inline] - fn shr(self, rhs: usize) -> BigInt { - let round_down = shr_round_down(&self, rhs); - let data = self.data >> rhs; - BigInt::from_biguint(self.sign, if round_down { data + 1u8 } else { data }) + fn shr(mut self, rhs: usize) -> BigInt { + self >>= rhs; + self } } @@ -709,12 +718,25 @@ impl<'a> Shr for &'a BigInt { #[inline] fn shr(self, rhs: usize) -> BigInt { - let round_down = shr_round_down(&self, rhs); + let round_down = shr_round_down(self, rhs); let data = &self.data >> rhs; BigInt::from_biguint(self.sign, if round_down { data + 1u8 } else { data }) } } +impl ShrAssign for BigInt { + #[inline] + fn shr_assign(&mut self, rhs: usize) { + let round_down = shr_round_down(self, rhs); + self.data >>= rhs; + if round_down { + self.data += 1u8; + } else if self.data.is_zero() { + self.sign = NoSign; + } + } +} + impl Zero for BigInt { #[inline] fn zero() -> BigInt { @@ -860,7 +882,17 @@ impl Add for BigInt { } } +impl<'a> AddAssign<&'a BigInt> for BigInt { + #[inline] + fn add_assign(&mut self, other: &BigInt) { + let n = mem::replace(self, BigInt::zero()); + *self = n + other; + } +} +forward_val_assign!(impl AddAssign for BigInt, add_assign); + promote_all_scalars!(impl Add for BigInt, add); +promote_all_scalars_assign!(impl AddAssign for BigInt, add_assign); forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigInt, add); forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigInt, add); @@ -881,6 +913,13 @@ impl Add for BigInt { } } } +impl AddAssign for BigInt { + #[inline] + fn add_assign(&mut self, other: BigDigit) { + let n = mem::replace(self, BigInt::zero()); + *self = n + other; + } +} impl Add for BigInt { type Output = BigInt; @@ -899,6 +938,13 @@ impl Add for BigInt { } } } +impl AddAssign for BigInt { + #[inline] + fn add_assign(&mut self, other: DoubleBigDigit) { + let n = mem::replace(self, BigInt::zero()); + *self = n + other; + } +} forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigInt, add); forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigInt, add); @@ -915,6 +961,16 @@ impl Add for BigInt { } } } +impl AddAssign for BigInt { + #[inline] + fn add_assign(&mut self, other: i32) { + if other >= 0 { + *self += other as u32; + } else { + *self -= i32_abs_as_u32(other); + } + } +} impl Add for BigInt { type Output = BigInt; @@ -928,6 +984,16 @@ impl Add for BigInt { } } } +impl AddAssign for BigInt { + #[inline] + fn add_assign(&mut self, other: i64) { + if other >= 0 { + *self += other as u64; + } else { + *self -= i64_abs_as_u64(other); + } + } +} // We want to forward to BigUint::sub, but it's not clear how that will go until // we compare both sign and magnitude. So we duplicate this body for every @@ -992,7 +1058,17 @@ impl Sub for BigInt { } } +impl<'a> SubAssign<&'a BigInt> for BigInt { + #[inline] + fn sub_assign(&mut self, other: &BigInt) { + let n = mem::replace(self, BigInt::zero()); + *self = n - other; + } +} +forward_val_assign!(impl SubAssign for BigInt, sub_assign); + promote_all_scalars!(impl Sub for BigInt, sub); +promote_all_scalars_assign!(impl SubAssign for BigInt, sub_assign); forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); @@ -1013,6 +1089,13 @@ impl Sub for BigInt { } } } +impl SubAssign for BigInt { + #[inline] + fn sub_assign(&mut self, other: BigDigit) { + let n = mem::replace(self, BigInt::zero()); + *self = n - other; + } +} impl Sub for BigDigit { type Output = BigInt; @@ -1040,6 +1123,13 @@ impl Sub for BigInt { } } } +impl SubAssign for BigInt { + #[inline] + fn sub_assign(&mut self, other: DoubleBigDigit) { + let n = mem::replace(self, BigInt::zero()); + *self = n - other; + } +} impl Sub for DoubleBigDigit { type Output = BigInt; @@ -1065,6 +1155,16 @@ impl Sub for BigInt { } } } +impl SubAssign for BigInt { + #[inline] + fn sub_assign(&mut self, other: i32) { + if other >= 0 { + *self -= other as u32; + } else { + *self += i32_abs_as_u32(other); + } + } +} impl Sub for i32 { type Output = BigInt; @@ -1091,6 +1191,16 @@ impl Sub for BigInt { } } } +impl SubAssign for BigInt { + #[inline] + fn sub_assign(&mut self, other: i64) { + if other >= 0 { + *self -= other as u64; + } else { + *self += i64_abs_as_u64(other); + } + } +} impl Sub for i64 { type Output = BigInt; @@ -1116,7 +1226,16 @@ impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt { } } +impl<'a> MulAssign<&'a BigInt> for BigInt { + #[inline] + fn mul_assign(&mut self, other: &BigInt) { + *self = &*self * other; + } +} +forward_val_assign!(impl MulAssign for BigInt, mul_assign); + promote_all_scalars!(impl Mul for BigInt, mul); +promote_all_scalars_assign!(impl MulAssign for BigInt, mul_assign); forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigInt, mul); forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigInt, mul); @@ -1129,6 +1248,16 @@ impl Mul for BigInt { } } +impl MulAssign for BigInt { + #[inline] + fn mul_assign(&mut self, other: BigDigit) { + self.data *= other; + if self.data.is_zero() { + self.sign = NoSign; + } + } +} + impl Mul for BigInt { type Output = BigInt; @@ -1138,6 +1267,16 @@ impl Mul for BigInt { } } +impl MulAssign for BigInt { + #[inline] + fn mul_assign(&mut self, other: DoubleBigDigit) { + self.data *= other; + if self.data.is_zero() { + self.sign = NoSign; + } + } +} + forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigInt, mul); forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigInt, mul); @@ -1154,6 +1293,18 @@ impl Mul for BigInt { } } +impl MulAssign for BigInt { + #[inline] + fn mul_assign(&mut self, other: i32) { + if other >= 0 { + *self *= other as u32; + } else { + self.sign = -self.sign; + *self *= i32_abs_as_u32(other); + } + } +} + impl Mul for BigInt { type Output = BigInt; @@ -1167,6 +1318,18 @@ impl Mul for BigInt { } } +impl MulAssign for BigInt { + #[inline] + fn mul_assign(&mut self, other: i64) { + if other >= 0 { + *self *= other as u64; + } else { + self.sign = -self.sign; + *self *= i64_abs_as_u64(other); + } + } +} + forward_all_binop_to_ref_ref!(impl Div for BigInt, div); impl<'a, 'b> Div<&'b BigInt> for &'a BigInt { @@ -1179,7 +1342,16 @@ impl<'a, 'b> Div<&'b BigInt> for &'a BigInt { } } +impl<'a> DivAssign<&'a BigInt> for BigInt { + #[inline] + fn div_assign(&mut self, other: &BigInt) { + *self = &*self / other; + } +} +forward_val_assign!(impl DivAssign for BigInt, div_assign); + promote_all_scalars!(impl Div for BigInt, div); +promote_all_scalars_assign!(impl DivAssign for BigInt, div_assign); forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); @@ -1192,6 +1364,16 @@ impl Div for BigInt { } } +impl DivAssign for BigInt { + #[inline] + fn div_assign(&mut self, other: BigDigit) { + self.data /= other; + if self.data.is_zero() { + self.sign = NoSign; + } + } +} + impl Div for BigDigit { type Output = BigInt; @@ -1210,6 +1392,16 @@ impl Div for BigInt { } } +impl DivAssign for BigInt { + #[inline] + fn div_assign(&mut self, other: DoubleBigDigit) { + self.data /= other; + if self.data.is_zero() { + self.sign = NoSign; + } + } +} + impl Div for DoubleBigDigit { type Output = BigInt; @@ -1235,6 +1427,18 @@ impl Div for BigInt { } } +impl DivAssign for BigInt { + #[inline] + fn div_assign(&mut self, other: i32) { + if other >= 0 { + *self /= other as u32; + } else { + self.sign = -self.sign; + *self /= i32_abs_as_u32(other); + } + } +} + impl Div for i32 { type Output = BigInt; @@ -1261,6 +1465,18 @@ impl Div for BigInt { } } +impl DivAssign for BigInt { + #[inline] + fn div_assign(&mut self, other: i64) { + if other >= 0 { + *self /= other as u64; + } else { + self.sign = -self.sign; + *self /= i64_abs_as_u64(other); + } + } +} + impl Div for i64 { type Output = BigInt; @@ -1286,7 +1502,16 @@ impl<'a, 'b> Rem<&'b BigInt> for &'a BigInt { } } +impl<'a> RemAssign<&'a BigInt> for BigInt { + #[inline] + fn rem_assign(&mut self, other: &BigInt) { + *self = &*self % other; + } +} +forward_val_assign!(impl RemAssign for BigInt, rem_assign); + promote_all_scalars!(impl Rem for BigInt, rem); +promote_all_scalars_assign!(impl RemAssign for BigInt, rem_assign); forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); @@ -1299,6 +1524,16 @@ impl Rem for BigInt { } } +impl RemAssign for BigInt { + #[inline] + fn rem_assign(&mut self, other: BigDigit) { + self.data %= other; + if self.data.is_zero() { + self.sign = NoSign; + } + } +} + impl Rem for BigDigit { type Output = BigInt; @@ -1317,6 +1552,16 @@ impl Rem for BigInt { } } +impl RemAssign for BigInt { + #[inline] + fn rem_assign(&mut self, other: DoubleBigDigit) { + self.data %= other; + if self.data.is_zero() { + self.sign = NoSign; + } + } +} + impl Rem for DoubleBigDigit { type Output = BigInt; @@ -1342,6 +1587,17 @@ impl Rem for BigInt { } } +impl RemAssign for BigInt { + #[inline] + fn rem_assign(&mut self, other: i32) { + if other >= 0 { + *self %= other as u32; + } else { + *self %= i32_abs_as_u32(other); + } + } +} + impl Rem for i32 { type Output = BigInt; @@ -1368,6 +1624,17 @@ impl Rem for BigInt { } } +impl RemAssign for BigInt { + #[inline] + fn rem_assign(&mut self, other: i64) { + if other >= 0 { + *self %= other as u64; + } else { + *self %= i64_abs_as_u64(other); + } + } +} + impl Rem for i64 { type Output = BigInt; diff --git a/src/biguint.rs b/src/biguint.rs index f67093cd..7bf9da21 100644 --- a/src/biguint.rs +++ b/src/biguint.rs @@ -378,7 +378,8 @@ impl<'a> Shl for &'a BigUint { impl ShlAssign for BigUint { #[inline] fn shl_assign(&mut self, rhs: usize) { - *self = biguint_shl(Cow::Borrowed(&*self), rhs); + let n = mem::replace(self, BigUint::zero()); + *self = n << rhs; } } diff --git a/src/macros.rs b/src/macros.rs index f20b8019..4b4eb5c4 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -266,6 +266,13 @@ macro_rules! promote_signed_scalars { } } +macro_rules! promote_signed_scalars_assign { + (impl $imp:ident for $res:ty, $method:ident) => { + promote_scalars_assign!(impl $imp for $res, $method, i8, i16); + promote_scalars_assign!(impl $imp for $res, $method, isize); + } +} + // Forward everything to ref-ref, when reusing storage is not helpful macro_rules! forward_all_binop_to_ref_ref { (impl $imp:ident for $res:ty, $method:ident) => { @@ -315,6 +322,13 @@ macro_rules! promote_all_scalars { } } +macro_rules! promote_all_scalars_assign { + (impl $imp:ident for $res:ty, $method:ident) => { + promote_unsigned_scalars_assign!(impl $imp for $res, $method); + promote_signed_scalars_assign!(impl $imp for $res, $method); + } +} + macro_rules! impl_sum_iter_type { ($res:ty) => { impl Sum for $res diff --git a/tests/bigint.rs b/tests/bigint.rs index 9bf91f99..e8193686 100644 --- a/tests/bigint.rs +++ b/tests/bigint.rs @@ -522,6 +522,15 @@ fn test_add() { assert_op!(b + nc == na); assert_op!(na + nb == nc); assert_op!(a + na == Zero::zero()); + + assert_assign_op!(a += b == c); + assert_assign_op!(b += a == c); + assert_assign_op!(c += na == b); + assert_assign_op!(c += nb == a); + assert_assign_op!(a += nc == nb); + assert_assign_op!(b += nc == na); + assert_assign_op!(na += nb == nc); + assert_assign_op!(a += na == Zero::zero()); } } @@ -542,6 +551,15 @@ fn test_sub() { assert_op!(a - nb == c); assert_op!(nc - na == nb); assert_op!(a - a == Zero::zero()); + + assert_assign_op!(c -= a == b); + assert_assign_op!(c -= b == a); + assert_assign_op!(nb -= a == nc); + assert_assign_op!(na -= b == nc); + assert_assign_op!(b -= na == c); + assert_assign_op!(a -= nb == c); + assert_assign_op!(nc -= na == nb); + assert_assign_op!(a -= a == Zero::zero()); } } @@ -560,6 +578,13 @@ fn test_mul() { assert_op!(na * b == nc); assert_op!(nb * a == nc); + + assert_assign_op!(a *= b == c); + assert_assign_op!(b *= a == c); + assert_assign_op!(na *= nb == c); + + assert_assign_op!(na *= b == nc); + assert_assign_op!(nb *= a == nc); } for elm in DIV_REM_QUADRUPLES.iter() { @@ -645,6 +670,8 @@ fn test_div_rem() { let (a, b, ans_q, ans_r) = (a.clone(), b.clone(), ans_q.clone(), ans_r.clone()); assert_op!(a / b == ans_q); assert_op!(a % b == ans_r); + assert_assign_op!(a /= b == ans_q); + assert_assign_op!(a %= b == ans_r); } fn check(a: &BigInt, b: &BigInt, q: &BigInt, r: &BigInt) {