diff --git a/src/bigint.rs b/src/bigint.rs index 8347e04..16caac4 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -877,6 +877,17 @@ fn i64_abs_as_u64(a: i64) -> u64 { } } +// A convenience method for getting the absolute value of an i128 in a u128. +#[cfg(has_i128)] +#[inline] +fn i128_abs_as_u128(a: i128) -> u128 { + if a == i128::min_value() { + a as u128 + } else { + a.abs() as u128 + } +} + // We want to forward to BigUint::add, but it's not clear how that will go until // we compare both sign and magnitude. So we duplicate this body for every // val/ref combination, deferring that decision to BigUint's own forwarding. @@ -951,14 +962,16 @@ 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); +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); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigInt, add); -impl Add for BigInt { +impl Add for BigInt { type Output = BigInt; #[inline] - fn add(self, other: BigDigit) -> BigInt { + fn add(self, other: u32) -> BigInt { match self.sign { NoSign => From::from(other), Plus => BigInt::from_biguint(Plus, self.data + other), @@ -970,19 +983,19 @@ impl Add for BigInt { } } } -impl AddAssign for BigInt { +impl AddAssign for BigInt { #[inline] - fn add_assign(&mut self, other: BigDigit) { + fn add_assign(&mut self, other: u32) { let n = mem::replace(self, BigInt::zero()); *self = n + other; } } -impl Add for BigInt { +impl Add for BigInt { type Output = BigInt; #[inline] - fn add(self, other: DoubleBigDigit) -> BigInt { + fn add(self, other: u64) -> BigInt { match self.sign { NoSign => From::from(other), Plus => BigInt::from_biguint(Plus, self.data + other), @@ -994,9 +1007,35 @@ impl Add for BigInt { } } } -impl AddAssign for BigInt { +impl AddAssign for BigInt { #[inline] - fn add_assign(&mut self, other: DoubleBigDigit) { + fn add_assign(&mut self, other: u64) { + let n = mem::replace(self, BigInt::zero()); + *self = n + other; + } +} + +#[cfg(has_i128)] +impl Add for BigInt { + type Output = BigInt; + + #[inline] + fn add(self, other: u128) -> BigInt { + match self.sign { + NoSign => From::from(other), + Plus => BigInt::from_biguint(Plus, self.data + other), + Minus => match self.data.cmp(&From::from(other)) { + Equal => Zero::zero(), + Less => BigInt::from_biguint(Plus, other - self.data), + Greater => BigInt::from_biguint(Minus, self.data - other), + }, + } + } +} +#[cfg(has_i128)] +impl AddAssign for BigInt { + #[inline] + fn add_assign(&mut self, other: u128) { let n = mem::replace(self, BigInt::zero()); *self = n + other; } @@ -1004,6 +1043,8 @@ impl AddAssign for BigInt { 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); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigInt, add); impl Add for BigInt { type Output = BigInt; @@ -1051,6 +1092,31 @@ impl AddAssign for BigInt { } } +#[cfg(has_i128)] +impl Add for BigInt { + type Output = BigInt; + + #[inline] + fn add(self, other: i128) -> BigInt { + if other >= 0 { + self + other as u128 + } else { + self - i128_abs_as_u128(other) + } + } +} +#[cfg(has_i128)] +impl AddAssign for BigInt { + #[inline] + fn add_assign(&mut self, other: i128) { + if other >= 0 { + *self += other as u128; + } else { + *self -= i128_abs_as_u128(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 // val/ref combination, deferring that decision to BigUint's own forwarding. @@ -1127,14 +1193,16 @@ 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); +forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); +forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); -impl Sub for BigInt { +impl Sub for BigInt { type Output = BigInt; #[inline] - fn sub(self, other: BigDigit) -> BigInt { + fn sub(self, other: u32) -> BigInt { match self.sign { NoSign => BigInt::from_biguint(Minus, From::from(other)), Minus => BigInt::from_biguint(Minus, self.data + other), @@ -1146,15 +1214,15 @@ impl Sub for BigInt { } } } -impl SubAssign for BigInt { +impl SubAssign for BigInt { #[inline] - fn sub_assign(&mut self, other: BigDigit) { + fn sub_assign(&mut self, other: u32) { let n = mem::replace(self, BigInt::zero()); *self = n - other; } } -impl Sub for BigDigit { +impl Sub for u32 { type Output = BigInt; #[inline] @@ -1163,11 +1231,29 @@ impl Sub for BigDigit { } } -impl Sub for BigInt { +impl Sub for u64 { type Output = BigInt; #[inline] - fn sub(self, other: DoubleBigDigit) -> BigInt { + fn sub(self, other: BigInt) -> BigInt { + -(other - self) + } +} +#[cfg(has_i128)] +impl Sub for u128 { + type Output = BigInt; + + #[inline] + fn sub(self, other: BigInt) -> BigInt { + -(other - self) + } +} + +impl Sub for BigInt { + type Output = BigInt; + + #[inline] + fn sub(self, other: u64) -> BigInt { match self.sign { NoSign => BigInt::from_biguint(Minus, From::from(other)), Minus => BigInt::from_biguint(Minus, self.data + other), @@ -1179,25 +1265,44 @@ impl Sub for BigInt { } } } -impl SubAssign for BigInt { +impl SubAssign for BigInt { #[inline] - fn sub_assign(&mut self, other: DoubleBigDigit) { + fn sub_assign(&mut self, other: u64) { let n = mem::replace(self, BigInt::zero()); *self = n - other; } } -impl Sub for DoubleBigDigit { +#[cfg(has_i128)] +impl Sub for BigInt { type Output = BigInt; #[inline] - fn sub(self, other: BigInt) -> BigInt { - -(other - self) + fn sub(self, other: u128) -> BigInt { + match self.sign { + NoSign => BigInt::from_biguint(Minus, From::from(other)), + Minus => BigInt::from_biguint(Minus, self.data + other), + Plus => match self.data.cmp(&From::from(other)) { + Equal => Zero::zero(), + Greater => BigInt::from_biguint(Plus, self.data - other), + Less => BigInt::from_biguint(Minus, other - self.data), + }, + } + } +} +#[cfg(has_i128)] +impl SubAssign for BigInt { + #[inline] + fn sub_assign(&mut self, other: u128) { + let n = mem::replace(self, BigInt::zero()); + *self = n - other; } } forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); impl Sub for BigInt { type Output = BigInt; @@ -1271,6 +1376,44 @@ impl Sub for i64 { } } +#[cfg(has_i128)] +impl Sub for BigInt { + type Output = BigInt; + + #[inline] + fn sub(self, other: i128) -> BigInt { + if other >= 0 { + self - other as u128 + } else { + self + i128_abs_as_u128(other) + } + } +} +#[cfg(has_i128)] +impl SubAssign for BigInt { + #[inline] + fn sub_assign(&mut self, other: i128) { + if other >= 0 { + *self -= other as u128; + } else { + *self += i128_abs_as_u128(other); + } + } +} +#[cfg(has_i128)] +impl Sub for i128 { + type Output = BigInt; + + #[inline] + fn sub(self, other: BigInt) -> BigInt { + if self >= 0 { + self as u128 - other + } else { + -other - i128_abs_as_u128(self) + } + } +} + forward_all_binop_to_ref_ref!(impl Mul for BigInt, mul); impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt { @@ -1292,21 +1435,23 @@ 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); +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); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigInt, mul); -impl Mul for BigInt { +impl Mul for BigInt { type Output = BigInt; #[inline] - fn mul(self, other: BigDigit) -> BigInt { + fn mul(self, other: u32) -> BigInt { BigInt::from_biguint(self.sign, self.data * other) } } -impl MulAssign for BigInt { +impl MulAssign for BigInt { #[inline] - fn mul_assign(&mut self, other: BigDigit) { + fn mul_assign(&mut self, other: u32) { self.data *= other; if self.data.is_zero() { self.sign = NoSign; @@ -1314,18 +1459,37 @@ impl MulAssign for BigInt { } } -impl Mul for BigInt { +impl Mul for BigInt { type Output = BigInt; #[inline] - fn mul(self, other: DoubleBigDigit) -> BigInt { + fn mul(self, other: u64) -> BigInt { BigInt::from_biguint(self.sign, self.data * other) } } -impl MulAssign for BigInt { +impl MulAssign for BigInt { #[inline] - fn mul_assign(&mut self, other: DoubleBigDigit) { + fn mul_assign(&mut self, other: u64) { + self.data *= other; + if self.data.is_zero() { + self.sign = NoSign; + } + } +} +#[cfg(has_i128)] +impl Mul for BigInt { + type Output = BigInt; + + #[inline] + fn mul(self, other: u128) -> BigInt { + BigInt::from_biguint(self.sign, self.data * other) + } +} +#[cfg(has_i128)] +impl MulAssign for BigInt { + #[inline] + fn mul_assign(&mut self, other: u128) { self.data *= other; if self.data.is_zero() { self.sign = NoSign; @@ -1335,6 +1499,8 @@ impl MulAssign for BigInt { 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); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigInt, mul); impl Mul for BigInt { type Output = BigInt; @@ -1385,6 +1551,31 @@ impl MulAssign for BigInt { } } } +#[cfg(has_i128)] +impl Mul for BigInt { + type Output = BigInt; + + #[inline] + fn mul(self, other: i128) -> BigInt { + if other >= 0 { + self * other as u128 + } else { + -(self * i128_abs_as_u128(other)) + } + } +} +#[cfg(has_i128)] +impl MulAssign for BigInt { + #[inline] + fn mul_assign(&mut self, other: i128) { + if other >= 0 { + *self *= other as u128; + } else { + self.sign = -self.sign; + *self *= i128_abs_as_u128(other); + } + } +} forward_all_binop_to_ref_ref!(impl Div for BigInt, div); @@ -1408,21 +1599,23 @@ 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); +forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); +forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); -impl Div for BigInt { +impl Div for BigInt { type Output = BigInt; #[inline] - fn div(self, other: BigDigit) -> BigInt { + fn div(self, other: u32) -> BigInt { BigInt::from_biguint(self.sign, self.data / other) } } -impl DivAssign for BigInt { +impl DivAssign for BigInt { #[inline] - fn div_assign(&mut self, other: BigDigit) { + fn div_assign(&mut self, other: u32) { self.data /= other; if self.data.is_zero() { self.sign = NoSign; @@ -1430,7 +1623,7 @@ impl DivAssign for BigInt { } } -impl Div for BigDigit { +impl Div for u32 { type Output = BigInt; #[inline] @@ -1439,18 +1632,18 @@ impl Div for BigDigit { } } -impl Div for BigInt { +impl Div for BigInt { type Output = BigInt; #[inline] - fn div(self, other: DoubleBigDigit) -> BigInt { + fn div(self, other: u64) -> BigInt { BigInt::from_biguint(self.sign, self.data / other) } } -impl DivAssign for BigInt { +impl DivAssign for BigInt { #[inline] - fn div_assign(&mut self, other: DoubleBigDigit) { + fn div_assign(&mut self, other: u64) { self.data /= other; if self.data.is_zero() { self.sign = NoSign; @@ -1458,7 +1651,38 @@ impl DivAssign for BigInt { } } -impl Div for DoubleBigDigit { +impl Div for u64 { + type Output = BigInt; + + #[inline] + fn div(self, other: BigInt) -> BigInt { + BigInt::from_biguint(other.sign, self / other.data) + } +} + +#[cfg(has_i128)] +impl Div for BigInt { + type Output = BigInt; + + #[inline] + fn div(self, other: u128) -> BigInt { + BigInt::from_biguint(self.sign, self.data / other) + } +} + +#[cfg(has_i128)] +impl DivAssign for BigInt { + #[inline] + fn div_assign(&mut self, other: u128) { + self.data /= other; + if self.data.is_zero() { + self.sign = NoSign; + } + } +} + +#[cfg(has_i128)] +impl Div for u128 { type Output = BigInt; #[inline] @@ -1469,6 +1693,8 @@ impl Div for DoubleBigDigit { forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); impl Div for BigInt { type Output = BigInt; @@ -1546,6 +1772,47 @@ impl Div for i64 { } } +#[cfg(has_i128)] +impl Div for BigInt { + type Output = BigInt; + + #[inline] + fn div(self, other: i128) -> BigInt { + if other >= 0 { + self / other as u128 + } else { + -(self / i128_abs_as_u128(other)) + } + } +} + +#[cfg(has_i128)] +impl DivAssign for BigInt { + #[inline] + fn div_assign(&mut self, other: i128) { + if other >= 0 { + *self /= other as u128; + } else { + self.sign = -self.sign; + *self /= i128_abs_as_u128(other); + } + } +} + +#[cfg(has_i128)] +impl Div for i128 { + type Output = BigInt; + + #[inline] + fn div(self, other: BigInt) -> BigInt { + if self >= 0 { + self as u128 / other + } else { + -(i128_abs_as_u128(self) / other) + } + } +} + forward_all_binop_to_ref_ref!(impl Rem for BigInt, rem); impl<'a, 'b> Rem<&'b BigInt> for &'a BigInt { @@ -1568,21 +1835,23 @@ 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); +forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); +forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); -impl Rem for BigInt { +impl Rem for BigInt { type Output = BigInt; #[inline] - fn rem(self, other: BigDigit) -> BigInt { + fn rem(self, other: u32) -> BigInt { BigInt::from_biguint(self.sign, self.data % other) } } -impl RemAssign for BigInt { +impl RemAssign for BigInt { #[inline] - fn rem_assign(&mut self, other: BigDigit) { + fn rem_assign(&mut self, other: u32) { self.data %= other; if self.data.is_zero() { self.sign = NoSign; @@ -1590,7 +1859,7 @@ impl RemAssign for BigInt { } } -impl Rem for BigDigit { +impl Rem for u32 { type Output = BigInt; #[inline] @@ -1599,18 +1868,18 @@ impl Rem for BigDigit { } } -impl Rem for BigInt { +impl Rem for BigInt { type Output = BigInt; #[inline] - fn rem(self, other: DoubleBigDigit) -> BigInt { + fn rem(self, other: u64) -> BigInt { BigInt::from_biguint(self.sign, self.data % other) } } -impl RemAssign for BigInt { +impl RemAssign for BigInt { #[inline] - fn rem_assign(&mut self, other: DoubleBigDigit) { + fn rem_assign(&mut self, other: u64) { self.data %= other; if self.data.is_zero() { self.sign = NoSign; @@ -1618,7 +1887,38 @@ impl RemAssign for BigInt { } } -impl Rem for DoubleBigDigit { +impl Rem for u64 { + type Output = BigInt; + + #[inline] + fn rem(self, other: BigInt) -> BigInt { + BigInt::from_biguint(Plus, self % other.data) + } +} + +#[cfg(has_i128)] +impl Rem for BigInt { + type Output = BigInt; + + #[inline] + fn rem(self, other: u128) -> BigInt { + BigInt::from_biguint(self.sign, self.data % other) + } +} + +#[cfg(has_i128)] +impl RemAssign for BigInt { + #[inline] + fn rem_assign(&mut self, other: u128) { + self.data %= other; + if self.data.is_zero() { + self.sign = NoSign; + } + } +} + +#[cfg(has_i128)] +impl Rem for u128 { type Output = BigInt; #[inline] @@ -1629,6 +1929,8 @@ impl Rem for DoubleBigDigit { forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); impl Rem for BigInt { type Output = BigInt; @@ -1704,6 +2006,44 @@ impl Rem for i64 { } } +#[cfg(has_i128)] +impl Rem for BigInt { + type Output = BigInt; + + #[inline] + fn rem(self, other: i128) -> BigInt { + if other >= 0 { + self % other as u128 + } else { + self % i128_abs_as_u128(other) + } + } +} +#[cfg(has_i128)] +impl RemAssign for BigInt { + #[inline] + fn rem_assign(&mut self, other: i128) { + if other >= 0 { + *self %= other as u128; + } else { + *self %= i128_abs_as_u128(other); + } + } +} +#[cfg(has_i128)] +impl Rem for i128 { + type Output = BigInt; + + #[inline] + fn rem(self, other: BigInt) -> BigInt { + if self >= 0 { + self as u128 % other + } else { + -(i128_abs_as_u128(self) % other) + } + } +} + impl Neg for BigInt { type Output = BigInt; diff --git a/src/biguint.rs b/src/biguint.rs index 6e715d1..1298c5d 100644 --- a/src/biguint.rs +++ b/src/biguint.rs @@ -24,7 +24,7 @@ use traits::{ ToPrimitive, Unsigned, Zero, }; -use big_digit::{self, BigDigit, DoubleBigDigit}; +use big_digit::{self, BigDigit}; #[path = "algorithms.rs"] mod algorithms; @@ -518,27 +518,30 @@ impl<'a> AddAssign<&'a BigUint> for BigUint { promote_unsigned_scalars!(impl Add for BigUint, add); promote_unsigned_scalars_assign!(impl AddAssign for BigUint, add_assign); -forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigUint, add); -forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigUint, add); +forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigUint, add); +forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigUint, add); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigUint, add); -impl Add for BigUint { +impl Add for BigUint { type Output = BigUint; #[inline] - fn add(mut self, other: BigDigit) -> BigUint { + fn add(mut self, other: u32) -> BigUint { self += other; self } } -impl AddAssign for BigUint { + +impl AddAssign for BigUint { #[inline] - fn add_assign(&mut self, other: BigDigit) { + fn add_assign(&mut self, other: u32) { if other != 0 { if self.data.len() == 0 { self.data.push(0); } - let carry = __add2(&mut self.data, &[other]); + let carry = __add2(&mut self.data, &[other as BigDigit]); if carry != 0 { self.data.push(carry); } @@ -546,18 +549,19 @@ impl AddAssign for BigUint { } } -impl Add for BigUint { +impl Add for BigUint { type Output = BigUint; #[inline] - fn add(mut self, other: DoubleBigDigit) -> BigUint { + fn add(mut self, other: u64) -> BigUint { self += other; self } } -impl AddAssign for BigUint { + +impl AddAssign for BigUint { #[inline] - fn add_assign(&mut self, other: DoubleBigDigit) { + fn add_assign(&mut self, other: u64) { let (hi, lo) = big_digit::from_doublebigdigit(other); if hi == 0 { *self += lo; @@ -574,6 +578,44 @@ impl AddAssign for BigUint { } } +#[cfg(has_i128)] +impl Add for BigUint { + type Output = BigUint; + + #[inline] + fn add(mut self, other: u128) -> BigUint { + self += other; + self + } +} + +#[cfg(has_i128)] +impl AddAssign for BigUint { + #[inline] + fn add_assign(&mut self, other: u128) { + if other <= u64::max_value() as u128 { + *self += other as u64 + } else { + let (a, b, c, d) = u32_from_u128(other); + let carry = if a > 0 { + while self.data.len() < 4 { + self.data.push(0); + } + __add2(&mut self.data, &[d, c, b, a]) + } else { + while self.data.len() < 3 { + self.data.push(0); + } + __add2(&mut self.data, &[d, c, b]) + }; + + if carry != 0 { + self.data.push(carry); + } + } + } +} + forward_val_val_binop!(impl Sub for BigUint, sub); forward_ref_ref_binop!(impl Sub for BigUint, sub); forward_val_assign!(impl SubAssign for BigUint, sub_assign); @@ -613,57 +655,61 @@ impl<'a> Sub for &'a BigUint { promote_unsigned_scalars!(impl Sub for BigUint, sub); promote_unsigned_scalars_assign!(impl SubAssign for BigUint, sub_assign); -forward_all_scalar_binop_to_val_val!(impl Sub for BigUint, sub); -forward_all_scalar_binop_to_val_val!(impl Sub for BigUint, sub); +forward_all_scalar_binop_to_val_val!(impl Sub for BigUint, sub); +forward_all_scalar_binop_to_val_val!(impl Sub for BigUint, sub); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val!(impl Sub for BigUint, sub); -impl Sub for BigUint { +impl Sub for BigUint { type Output = BigUint; #[inline] - fn sub(mut self, other: BigDigit) -> BigUint { + fn sub(mut self, other: u32) -> BigUint { self -= other; self } } -impl SubAssign for BigUint { - fn sub_assign(&mut self, other: BigDigit) { - sub2(&mut self.data[..], &[other]); +impl SubAssign for BigUint { + fn sub_assign(&mut self, other: u32) { + sub2(&mut self.data[..], &[other as BigDigit]); self.normalize(); } } -impl Sub for BigDigit { +impl Sub for u32 { type Output = BigUint; #[inline] fn sub(self, mut other: BigUint) -> BigUint { if other.data.len() == 0 { - other.data.push(self); + other.data.push(self as BigDigit); } else { - sub2rev(&[self], &mut other.data[..]); + sub2rev(&[self as BigDigit], &mut other.data[..]); } other.normalized() } } -impl Sub for BigUint { +impl Sub for BigUint { type Output = BigUint; #[inline] - fn sub(mut self, other: DoubleBigDigit) -> BigUint { + fn sub(mut self, other: u64) -> BigUint { self -= other; self } } -impl SubAssign for BigUint { - fn sub_assign(&mut self, other: DoubleBigDigit) { + +impl SubAssign for BigUint { + #[inline] + fn sub_assign(&mut self, other: u64) { let (hi, lo) = big_digit::from_doublebigdigit(other); sub2(&mut self.data[..], &[lo, hi]); self.normalize(); } } -impl Sub for DoubleBigDigit { +impl Sub for u64 { type Output = BigUint; #[inline] @@ -678,6 +724,41 @@ impl Sub for DoubleBigDigit { } } +#[cfg(has_i128)] +impl Sub for BigUint { + type Output = BigUint; + + #[inline] + fn sub(mut self, other: u128) -> BigUint { + self -= other; + self + } +} +#[cfg(has_i128)] +impl SubAssign for BigUint { + fn sub_assign(&mut self, other: u128) { + let (a, b, c, d) = u32_from_u128(other); + sub2(&mut self.data[..], &[d, c, b, a]); + self.normalize(); + } +} + +#[cfg(has_i128)] +impl Sub for u128 { + type Output = BigUint; + + #[inline] + fn sub(self, mut other: BigUint) -> BigUint { + while other.data.len() < 4 { + other.data.push(0); + } + + let (a, b, c, d) = u32_from_u128(self); + sub2rev(&[d, c, b, a], &mut other.data[..]); + other.normalized() + } +} + forward_all_binop_to_ref_ref!(impl Mul for BigUint, mul); forward_val_assign!(impl MulAssign for BigUint, mul_assign); @@ -698,25 +779,27 @@ impl<'a> MulAssign<&'a BigUint> for BigUint { promote_unsigned_scalars!(impl Mul for BigUint, mul); promote_unsigned_scalars_assign!(impl MulAssign for BigUint, mul_assign); -forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigUint, mul); -forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigUint, mul); +forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigUint, mul); +forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigUint, mul); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigUint, mul); -impl Mul for BigUint { +impl Mul for BigUint { type Output = BigUint; #[inline] - fn mul(mut self, other: BigDigit) -> BigUint { + fn mul(mut self, other: u32) -> BigUint { self *= other; self } } -impl MulAssign for BigUint { +impl MulAssign for BigUint { #[inline] - fn mul_assign(&mut self, other: BigDigit) { + fn mul_assign(&mut self, other: u32) { if other == 0 { self.data.clear(); } else { - let carry = scalar_mul(&mut self.data[..], other); + let carry = scalar_mul(&mut self.data[..], other as BigDigit); if carry != 0 { self.data.push(carry); } @@ -724,21 +807,21 @@ impl MulAssign for BigUint { } } -impl Mul for BigUint { +impl Mul for BigUint { type Output = BigUint; #[inline] - fn mul(mut self, other: DoubleBigDigit) -> BigUint { + fn mul(mut self, other: u64) -> BigUint { self *= other; self } } -impl MulAssign for BigUint { +impl MulAssign for BigUint { #[inline] - fn mul_assign(&mut self, other: DoubleBigDigit) { + fn mul_assign(&mut self, other: u64) { if other == 0 { self.data.clear(); - } else if other <= BigDigit::max_value() as DoubleBigDigit { + } else if other <= BigDigit::max_value() as u64 { *self *= other as BigDigit } else { let (hi, lo) = big_digit::from_doublebigdigit(other); @@ -747,6 +830,31 @@ impl MulAssign for BigUint { } } +#[cfg(has_i128)] +impl Mul for BigUint { + type Output = BigUint; + + #[inline] + fn mul(mut self, other: u128) -> BigUint { + self *= other; + self + } +} +#[cfg(has_i128)] +impl MulAssign for BigUint { + #[inline] + fn mul_assign(&mut self, other: u128) { + if other == 0 { + self.data.clear(); + } else if other <= BigDigit::max_value() as u128 { + *self *= other as BigDigit + } else { + let (a, b, c, d) = u32_from_u128(other); + *self = mul3(&self.data[..], &[d, c, b, a]) + } + } +} + forward_all_binop_to_ref_ref!(impl Div for BigUint, div); forward_val_assign!(impl DivAssign for BigUint, div_assign); @@ -768,55 +876,57 @@ impl<'a> DivAssign<&'a BigUint> for BigUint { promote_unsigned_scalars!(impl Div for BigUint, div); promote_unsigned_scalars_assign!(impl DivAssign for BigUint, div_assign); -forward_all_scalar_binop_to_val_val!(impl Div for BigUint, div); -forward_all_scalar_binop_to_val_val!(impl Div for BigUint, div); +forward_all_scalar_binop_to_val_val!(impl Div for BigUint, div); +forward_all_scalar_binop_to_val_val!(impl Div for BigUint, div); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val!(impl Div for BigUint, div); -impl Div for BigUint { +impl Div for BigUint { type Output = BigUint; #[inline] - fn div(self, other: BigDigit) -> BigUint { - let (q, _) = div_rem_digit(self, other); + fn div(self, other: u32) -> BigUint { + let (q, _) = div_rem_digit(self, other as BigDigit); q } } -impl DivAssign for BigUint { +impl DivAssign for BigUint { #[inline] - fn div_assign(&mut self, other: BigDigit) { + fn div_assign(&mut self, other: u32) { *self = &*self / other; } } -impl Div for BigDigit { +impl Div for u32 { type Output = BigUint; #[inline] fn div(self, other: BigUint) -> BigUint { match other.data.len() { 0 => panic!(), - 1 => From::from(self / other.data[0]), + 1 => From::from(self as BigDigit / other.data[0]), _ => Zero::zero(), } } } -impl Div for BigUint { +impl Div for BigUint { type Output = BigUint; #[inline] - fn div(self, other: DoubleBigDigit) -> BigUint { + fn div(self, other: u64) -> BigUint { let (q, _) = self.div_rem(&From::from(other)); q } } -impl DivAssign for BigUint { +impl DivAssign for BigUint { #[inline] - fn div_assign(&mut self, other: DoubleBigDigit) { + fn div_assign(&mut self, other: u64) { *self = &*self / other; } } -impl Div for DoubleBigDigit { +impl Div for u64 { type Output = BigUint; #[inline] @@ -830,6 +940,45 @@ impl Div for DoubleBigDigit { } } +#[cfg(has_i128)] +impl Div for BigUint { + type Output = BigUint; + + #[inline] + fn div(self, other: u128) -> BigUint { + let (q, _) = self.div_rem(&From::from(other)); + q + } +} +#[cfg(has_i128)] +impl DivAssign for BigUint { + #[inline] + fn div_assign(&mut self, other: u128) { + *self = &*self / other; + } +} + +#[cfg(has_i128)] +impl Div for u128 { + type Output = BigUint; + + #[inline] + fn div(self, other: BigUint) -> BigUint { + match other.data.len() { + 0 => panic!(), + 1 => From::from(self / other.data[0] as u128), + 2 => From::from( + self / big_digit::to_doublebigdigit(other.data[1], other.data[0]) as u128, + ), + 3 => From::from(self / u32_to_u128(0, other.data[2], other.data[1], other.data[0])), + 4 => From::from( + self / u32_to_u128(other.data[3], other.data[2], other.data[1], other.data[0]), + ), + _ => Zero::zero(), + } + } +} + forward_all_binop_to_ref_ref!(impl Rem for BigUint, rem); forward_val_assign!(impl RemAssign for BigUint, rem_assign); @@ -851,26 +1000,28 @@ impl<'a> RemAssign<&'a BigUint> for BigUint { promote_unsigned_scalars!(impl Rem for BigUint, rem); promote_unsigned_scalars_assign!(impl RemAssign for BigUint, rem_assign); -forward_all_scalar_binop_to_val_val!(impl Rem for BigUint, rem); -forward_all_scalar_binop_to_val_val!(impl Rem for BigUint, rem); +forward_all_scalar_binop_to_val_val!(impl Rem for BigUint, rem); +forward_all_scalar_binop_to_val_val!(impl Rem for BigUint, rem); +#[cfg(has_i128)] +forward_all_scalar_binop_to_val_val!(impl Rem for BigUint, rem); -impl Rem for BigUint { +impl Rem for BigUint { type Output = BigUint; #[inline] - fn rem(self, other: BigDigit) -> BigUint { - let (_, r) = div_rem_digit(self, other); + fn rem(self, other: u32) -> BigUint { + let (_, r) = div_rem_digit(self, other as BigDigit); From::from(r) } } -impl RemAssign for BigUint { +impl RemAssign for BigUint { #[inline] - fn rem_assign(&mut self, other: BigDigit) { + fn rem_assign(&mut self, other: u32) { *self = &*self % other; } } -impl Rem for BigDigit { +impl Rem for u32 { type Output = BigUint; #[inline] @@ -896,34 +1047,67 @@ macro_rules! impl_rem_assign_scalar { } } // we can scalar %= BigUint for any scalar, including signed types +#[cfg(has_i128)] +impl_rem_assign_scalar!(u128, to_u128); impl_rem_assign_scalar!(usize, to_usize); impl_rem_assign_scalar!(u64, to_u64); impl_rem_assign_scalar!(u32, to_u32); impl_rem_assign_scalar!(u16, to_u16); impl_rem_assign_scalar!(u8, to_u8); +#[cfg(has_i128)] +impl_rem_assign_scalar!(i128, to_i128); impl_rem_assign_scalar!(isize, to_isize); impl_rem_assign_scalar!(i64, to_i64); impl_rem_assign_scalar!(i32, to_i32); impl_rem_assign_scalar!(i16, to_i16); impl_rem_assign_scalar!(i8, to_i8); -impl Rem for BigUint { +impl Rem for BigUint { type Output = BigUint; #[inline] - fn rem(self, other: DoubleBigDigit) -> BigUint { + fn rem(self, other: u64) -> BigUint { let (_, r) = self.div_rem(&From::from(other)); r } } -impl RemAssign for BigUint { +impl RemAssign for BigUint { #[inline] - fn rem_assign(&mut self, other: DoubleBigDigit) { + fn rem_assign(&mut self, other: u64) { *self = &*self % other; } } -impl Rem for DoubleBigDigit { +impl Rem for u64 { + type Output = BigUint; + + #[inline] + fn rem(mut self, other: BigUint) -> BigUint { + self %= other; + From::from(self) + } +} + +#[cfg(has_i128)] +impl Rem for BigUint { + type Output = BigUint; + + #[inline] + fn rem(self, other: u128) -> BigUint { + let (_, r) = self.div_rem(&From::from(other)); + r + } +} +#[cfg(has_i128)] +impl RemAssign for BigUint { + #[inline] + fn rem_assign(&mut self, other: u128) { + *self = &*self % other; + } +} + +#[cfg(has_i128)] +impl Rem for u128 { type Output = BigUint; #[inline] @@ -1247,10 +1431,10 @@ impl ToPrimitive for BigUint { return None; } - ret += (*i as u128) << bits; + ret |= (*i as u128) << bits; bits += big_digit::BITS; } - + println!("{:?} -> {}", self, ret); Some(ret) } @@ -1975,6 +2159,25 @@ impl IntDigits for BigUint { } } +/// Combine four `u32`s into a single `u128`. +#[cfg(has_i128)] +#[inline] +fn u32_to_u128(a: u32, b: u32, c: u32, d: u32) -> u128 { + u128::from(d) | (u128::from(c) << 32) | (u128::from(b) << 64) | (u128::from(a) << 96) +} + +/// Split a single `u128` into four `u32`. +#[cfg(has_i128)] +#[inline] +fn u32_from_u128(n: u128) -> (u32, u32, u32, u32) { + ( + (n >> 96) as u32, + (n >> 64) as u32, + (n >> 32) as u32, + n as u32, + ) +} + #[cfg(feature = "serde")] impl serde::Serialize for BigUint { fn serialize(&self, serializer: S) -> Result @@ -2596,3 +2799,55 @@ fn test_assign_from_slice() { check(&[0, 0, 1, 2, 0, 0], &[0, 0, 1, 2]); check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]); } + +#[cfg(has_i128)] +#[test] +fn test_u32_u128() { + assert_eq!(u32_from_u128(0u128), (0, 0, 0, 0)); + assert_eq!( + u32_from_u128(u128::max_value()), + ( + u32::max_value(), + u32::max_value(), + u32::max_value(), + u32::max_value() + ) + ); + + assert_eq!( + u32_from_u128(u32::max_value() as u128), + (0, 0, 0, u32::max_value()) + ); + + assert_eq!( + u32_from_u128(u64::max_value() as u128), + (0, 0, u32::max_value(), u32::max_value()) + ); + + assert_eq!( + u32_from_u128((u64::max_value() as u128) + u32::max_value() as u128), + (0, 1, 0, u32::max_value() - 1) + ); + + assert_eq!(u32_from_u128(36_893_488_151_714_070_528), (0, 2, 1, 0)); +} + +#[cfg(has_i128)] +#[test] +fn test_u128_u32_roundtrip() { + // roundtrips + let values = vec![ + 0u128, + 1u128, + u64::max_value() as u128 * 3, + u32::max_value() as u128, + u64::max_value() as u128, + (u64::max_value() as u128) + u32::max_value() as u128, + u128::max_value(), + ]; + + for val in &values { + let (a, b, c, d) = u32_from_u128(*val); + assert_eq!(u32_to_u128(a, b, c, d), *val); + } +} diff --git a/tests/consts/mod.rs b/tests/consts/mod.rs index df22a68..87805d5 100644 --- a/tests/consts/mod.rs +++ b/tests/consts/mod.rs @@ -13,6 +13,7 @@ pub const SUM_TRIPLES: &'static [(&'static [u32], &'static [u32], &'static [u32] (&[N1, N1], &[N1, N1], &[N2, N1, 1]), (&[1, 1, 1], &[N1, N1], &[0, 1, 2]), (&[2, 2, 1], &[N1, N2], &[1, 1, 2]), + (&[1, 2, 2, 1], &[N1, N2], &[0, 1, 3, 1]), ]; pub const M: u32 = ::std::u32::MAX; diff --git a/tests/macros/mod.rs b/tests/macros/mod.rs index 90606ec..d848b29 100644 --- a/tests/macros/mod.rs +++ b/tests/macros/mod.rs @@ -35,6 +35,7 @@ macro_rules! assert_scalar_op { }; } +#[cfg(not(has_i128))] macro_rules! assert_unsigned_scalar_op { ($left:ident $op:tt $right:ident == $expected:expr) => { assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize) @@ -42,6 +43,15 @@ macro_rules! assert_unsigned_scalar_op { }; } +#[cfg(has_i128)] +macro_rules! assert_unsigned_scalar_op { + ($left:ident $op:tt $right:ident == $expected:expr) => { + assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, to_u128) + $left $op $right == $expected); + }; +} + +#[cfg(not(has_i128))] macro_rules! assert_signed_scalar_op { ($left:ident $op:tt $right:ident == $expected:expr) => { assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, @@ -49,3 +59,12 @@ macro_rules! assert_signed_scalar_op { $left $op $right == $expected); }; } + +#[cfg(has_i128)] +macro_rules! assert_signed_scalar_op { + ($left:ident $op:tt $right:ident == $expected:expr) => { + assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, to_u128, + to_i8, to_i16, to_i32, to_i64, to_isize, to_i128) + $left $op $right == $expected); + }; +}