feat: implement operators with 128bit

This commit is contained in:
dignifiedquire 2018-07-21 18:42:30 +02:00
parent 1a316783b5
commit 35939287b9
4 changed files with 741 additions and 126 deletions

View File

@ -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 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 // we compare both sign and magnitude. So we duplicate this body for every
// val/ref combination, deferring that decision to BigUint's own forwarding. // 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!(impl Add for BigInt, add);
promote_all_scalars_assign!(impl AddAssign for BigInt, add_assign); promote_all_scalars_assign!(impl AddAssign for BigInt, add_assign);
forward_all_scalar_binop_to_val_val_commutative!(impl Add<BigDigit> for BigInt, add); forward_all_scalar_binop_to_val_val_commutative!(impl Add<u32> for BigInt, add);
forward_all_scalar_binop_to_val_val_commutative!(impl Add<DoubleBigDigit> for BigInt, add); forward_all_scalar_binop_to_val_val_commutative!(impl Add<u64> for BigInt, add);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val_commutative!(impl Add<u128> for BigInt, add);
impl Add<BigDigit> for BigInt { impl Add<u32> for BigInt {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
fn add(self, other: BigDigit) -> BigInt { fn add(self, other: u32) -> BigInt {
match self.sign { match self.sign {
NoSign => From::from(other), NoSign => From::from(other),
Plus => BigInt::from_biguint(Plus, self.data + other), Plus => BigInt::from_biguint(Plus, self.data + other),
@ -970,19 +983,19 @@ impl Add<BigDigit> for BigInt {
} }
} }
} }
impl AddAssign<BigDigit> for BigInt { impl AddAssign<u32> for BigInt {
#[inline] #[inline]
fn add_assign(&mut self, other: BigDigit) { fn add_assign(&mut self, other: u32) {
let n = mem::replace(self, BigInt::zero()); let n = mem::replace(self, BigInt::zero());
*self = n + other; *self = n + other;
} }
} }
impl Add<DoubleBigDigit> for BigInt { impl Add<u64> for BigInt {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
fn add(self, other: DoubleBigDigit) -> BigInt { fn add(self, other: u64) -> BigInt {
match self.sign { match self.sign {
NoSign => From::from(other), NoSign => From::from(other),
Plus => BigInt::from_biguint(Plus, self.data + other), Plus => BigInt::from_biguint(Plus, self.data + other),
@ -994,9 +1007,35 @@ impl Add<DoubleBigDigit> for BigInt {
} }
} }
} }
impl AddAssign<DoubleBigDigit> for BigInt { impl AddAssign<u64> for BigInt {
#[inline] #[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<u128> 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<u128> for BigInt {
#[inline]
fn add_assign(&mut self, other: u128) {
let n = mem::replace(self, BigInt::zero()); let n = mem::replace(self, BigInt::zero());
*self = n + other; *self = n + other;
} }
@ -1004,6 +1043,8 @@ impl AddAssign<DoubleBigDigit> for BigInt {
forward_all_scalar_binop_to_val_val_commutative!(impl Add<i32> for BigInt, add); forward_all_scalar_binop_to_val_val_commutative!(impl Add<i32> for BigInt, add);
forward_all_scalar_binop_to_val_val_commutative!(impl Add<i64> for BigInt, add); forward_all_scalar_binop_to_val_val_commutative!(impl Add<i64> for BigInt, add);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val_commutative!(impl Add<i128> for BigInt, add);
impl Add<i32> for BigInt { impl Add<i32> for BigInt {
type Output = BigInt; type Output = BigInt;
@ -1051,6 +1092,31 @@ impl AddAssign<i64> for BigInt {
} }
} }
#[cfg(has_i128)]
impl Add<i128> 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<i128> 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 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 // we compare both sign and magnitude. So we duplicate this body for every
// val/ref combination, deferring that decision to BigUint's own forwarding. // 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!(impl Sub for BigInt, sub);
promote_all_scalars_assign!(impl SubAssign for BigInt, sub_assign); promote_all_scalars_assign!(impl SubAssign for BigInt, sub_assign);
forward_all_scalar_binop_to_val_val!(impl Sub<BigDigit> for BigInt, sub); forward_all_scalar_binop_to_val_val!(impl Sub<u32> for BigInt, sub);
forward_all_scalar_binop_to_val_val!(impl Sub<DoubleBigDigit> for BigInt, sub); forward_all_scalar_binop_to_val_val!(impl Sub<u64> for BigInt, sub);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val!(impl Sub<u128> for BigInt, sub);
impl Sub<BigDigit> for BigInt { impl Sub<u32> for BigInt {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
fn sub(self, other: BigDigit) -> BigInt { fn sub(self, other: u32) -> BigInt {
match self.sign { match self.sign {
NoSign => BigInt::from_biguint(Minus, From::from(other)), NoSign => BigInt::from_biguint(Minus, From::from(other)),
Minus => BigInt::from_biguint(Minus, self.data + other), Minus => BigInt::from_biguint(Minus, self.data + other),
@ -1146,15 +1214,15 @@ impl Sub<BigDigit> for BigInt {
} }
} }
} }
impl SubAssign<BigDigit> for BigInt { impl SubAssign<u32> for BigInt {
#[inline] #[inline]
fn sub_assign(&mut self, other: BigDigit) { fn sub_assign(&mut self, other: u32) {
let n = mem::replace(self, BigInt::zero()); let n = mem::replace(self, BigInt::zero());
*self = n - other; *self = n - other;
} }
} }
impl Sub<BigInt> for BigDigit { impl Sub<BigInt> for u32 {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
@ -1163,11 +1231,29 @@ impl Sub<BigInt> for BigDigit {
} }
} }
impl Sub<DoubleBigDigit> for BigInt { impl Sub<BigInt> for u64 {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
fn sub(self, other: DoubleBigDigit) -> BigInt { fn sub(self, other: BigInt) -> BigInt {
-(other - self)
}
}
#[cfg(has_i128)]
impl Sub<BigInt> for u128 {
type Output = BigInt;
#[inline]
fn sub(self, other: BigInt) -> BigInt {
-(other - self)
}
}
impl Sub<u64> for BigInt {
type Output = BigInt;
#[inline]
fn sub(self, other: u64) -> BigInt {
match self.sign { match self.sign {
NoSign => BigInt::from_biguint(Minus, From::from(other)), NoSign => BigInt::from_biguint(Minus, From::from(other)),
Minus => BigInt::from_biguint(Minus, self.data + other), Minus => BigInt::from_biguint(Minus, self.data + other),
@ -1179,25 +1265,44 @@ impl Sub<DoubleBigDigit> for BigInt {
} }
} }
} }
impl SubAssign<DoubleBigDigit> for BigInt { impl SubAssign<u64> for BigInt {
#[inline] #[inline]
fn sub_assign(&mut self, other: DoubleBigDigit) { fn sub_assign(&mut self, other: u64) {
let n = mem::replace(self, BigInt::zero()); let n = mem::replace(self, BigInt::zero());
*self = n - other; *self = n - other;
} }
} }
impl Sub<BigInt> for DoubleBigDigit { #[cfg(has_i128)]
impl Sub<u128> for BigInt {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
fn sub(self, other: BigInt) -> BigInt { fn sub(self, other: u128) -> BigInt {
-(other - self) 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<u128> 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<i32> for BigInt, sub); forward_all_scalar_binop_to_val_val!(impl Sub<i32> for BigInt, sub);
forward_all_scalar_binop_to_val_val!(impl Sub<i64> for BigInt, sub); forward_all_scalar_binop_to_val_val!(impl Sub<i64> for BigInt, sub);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val!(impl Sub<i128> for BigInt, sub);
impl Sub<i32> for BigInt { impl Sub<i32> for BigInt {
type Output = BigInt; type Output = BigInt;
@ -1271,6 +1376,44 @@ impl Sub<BigInt> for i64 {
} }
} }
#[cfg(has_i128)]
impl Sub<i128> 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<i128> 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<BigInt> 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); forward_all_binop_to_ref_ref!(impl Mul for BigInt, mul);
impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt { 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!(impl Mul for BigInt, mul);
promote_all_scalars_assign!(impl MulAssign for BigInt, mul_assign); promote_all_scalars_assign!(impl MulAssign for BigInt, mul_assign);
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<BigDigit> for BigInt, mul); forward_all_scalar_binop_to_val_val_commutative!(impl Mul<u32> for BigInt, mul);
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<DoubleBigDigit> for BigInt, mul); forward_all_scalar_binop_to_val_val_commutative!(impl Mul<u64> for BigInt, mul);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<u128> for BigInt, mul);
impl Mul<BigDigit> for BigInt { impl Mul<u32> for BigInt {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
fn mul(self, other: BigDigit) -> BigInt { fn mul(self, other: u32) -> BigInt {
BigInt::from_biguint(self.sign, self.data * other) BigInt::from_biguint(self.sign, self.data * other)
} }
} }
impl MulAssign<BigDigit> for BigInt { impl MulAssign<u32> for BigInt {
#[inline] #[inline]
fn mul_assign(&mut self, other: BigDigit) { fn mul_assign(&mut self, other: u32) {
self.data *= other; self.data *= other;
if self.data.is_zero() { if self.data.is_zero() {
self.sign = NoSign; self.sign = NoSign;
@ -1314,18 +1459,37 @@ impl MulAssign<BigDigit> for BigInt {
} }
} }
impl Mul<DoubleBigDigit> for BigInt { impl Mul<u64> for BigInt {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
fn mul(self, other: DoubleBigDigit) -> BigInt { fn mul(self, other: u64) -> BigInt {
BigInt::from_biguint(self.sign, self.data * other) BigInt::from_biguint(self.sign, self.data * other)
} }
} }
impl MulAssign<DoubleBigDigit> for BigInt { impl MulAssign<u64> for BigInt {
#[inline] #[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<u128> 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<u128> for BigInt {
#[inline]
fn mul_assign(&mut self, other: u128) {
self.data *= other; self.data *= other;
if self.data.is_zero() { if self.data.is_zero() {
self.sign = NoSign; self.sign = NoSign;
@ -1335,6 +1499,8 @@ impl MulAssign<DoubleBigDigit> for BigInt {
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<i32> for BigInt, mul); forward_all_scalar_binop_to_val_val_commutative!(impl Mul<i32> for BigInt, mul);
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<i64> for BigInt, mul); forward_all_scalar_binop_to_val_val_commutative!(impl Mul<i64> for BigInt, mul);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<i128> for BigInt, mul);
impl Mul<i32> for BigInt { impl Mul<i32> for BigInt {
type Output = BigInt; type Output = BigInt;
@ -1385,6 +1551,31 @@ impl MulAssign<i64> for BigInt {
} }
} }
} }
#[cfg(has_i128)]
impl Mul<i128> 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<i128> 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); 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!(impl Div for BigInt, div);
promote_all_scalars_assign!(impl DivAssign for BigInt, div_assign); promote_all_scalars_assign!(impl DivAssign for BigInt, div_assign);
forward_all_scalar_binop_to_val_val!(impl Div<BigDigit> for BigInt, div); forward_all_scalar_binop_to_val_val!(impl Div<u32> for BigInt, div);
forward_all_scalar_binop_to_val_val!(impl Div<DoubleBigDigit> for BigInt, div); forward_all_scalar_binop_to_val_val!(impl Div<u64> for BigInt, div);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val!(impl Div<u128> for BigInt, div);
impl Div<BigDigit> for BigInt { impl Div<u32> for BigInt {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
fn div(self, other: BigDigit) -> BigInt { fn div(self, other: u32) -> BigInt {
BigInt::from_biguint(self.sign, self.data / other) BigInt::from_biguint(self.sign, self.data / other)
} }
} }
impl DivAssign<BigDigit> for BigInt { impl DivAssign<u32> for BigInt {
#[inline] #[inline]
fn div_assign(&mut self, other: BigDigit) { fn div_assign(&mut self, other: u32) {
self.data /= other; self.data /= other;
if self.data.is_zero() { if self.data.is_zero() {
self.sign = NoSign; self.sign = NoSign;
@ -1430,7 +1623,7 @@ impl DivAssign<BigDigit> for BigInt {
} }
} }
impl Div<BigInt> for BigDigit { impl Div<BigInt> for u32 {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
@ -1439,18 +1632,18 @@ impl Div<BigInt> for BigDigit {
} }
} }
impl Div<DoubleBigDigit> for BigInt { impl Div<u64> for BigInt {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
fn div(self, other: DoubleBigDigit) -> BigInt { fn div(self, other: u64) -> BigInt {
BigInt::from_biguint(self.sign, self.data / other) BigInt::from_biguint(self.sign, self.data / other)
} }
} }
impl DivAssign<DoubleBigDigit> for BigInt { impl DivAssign<u64> for BigInt {
#[inline] #[inline]
fn div_assign(&mut self, other: DoubleBigDigit) { fn div_assign(&mut self, other: u64) {
self.data /= other; self.data /= other;
if self.data.is_zero() { if self.data.is_zero() {
self.sign = NoSign; self.sign = NoSign;
@ -1458,7 +1651,38 @@ impl DivAssign<DoubleBigDigit> for BigInt {
} }
} }
impl Div<BigInt> for DoubleBigDigit { impl Div<BigInt> 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<u128> 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<u128> 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<BigInt> for u128 {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
@ -1469,6 +1693,8 @@ impl Div<BigInt> for DoubleBigDigit {
forward_all_scalar_binop_to_val_val!(impl Div<i32> for BigInt, div); forward_all_scalar_binop_to_val_val!(impl Div<i32> for BigInt, div);
forward_all_scalar_binop_to_val_val!(impl Div<i64> for BigInt, div); forward_all_scalar_binop_to_val_val!(impl Div<i64> for BigInt, div);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val!(impl Div<i128> for BigInt, div);
impl Div<i32> for BigInt { impl Div<i32> for BigInt {
type Output = BigInt; type Output = BigInt;
@ -1546,6 +1772,47 @@ impl Div<BigInt> for i64 {
} }
} }
#[cfg(has_i128)]
impl Div<i128> 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<i128> 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<BigInt> 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); forward_all_binop_to_ref_ref!(impl Rem for BigInt, rem);
impl<'a, 'b> Rem<&'b BigInt> for &'a BigInt { 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!(impl Rem for BigInt, rem);
promote_all_scalars_assign!(impl RemAssign for BigInt, rem_assign); promote_all_scalars_assign!(impl RemAssign for BigInt, rem_assign);
forward_all_scalar_binop_to_val_val!(impl Rem<BigDigit> for BigInt, rem); forward_all_scalar_binop_to_val_val!(impl Rem<u32> for BigInt, rem);
forward_all_scalar_binop_to_val_val!(impl Rem<DoubleBigDigit> for BigInt, rem); forward_all_scalar_binop_to_val_val!(impl Rem<u64> for BigInt, rem);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val!(impl Rem<u128> for BigInt, rem);
impl Rem<BigDigit> for BigInt { impl Rem<u32> for BigInt {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
fn rem(self, other: BigDigit) -> BigInt { fn rem(self, other: u32) -> BigInt {
BigInt::from_biguint(self.sign, self.data % other) BigInt::from_biguint(self.sign, self.data % other)
} }
} }
impl RemAssign<BigDigit> for BigInt { impl RemAssign<u32> for BigInt {
#[inline] #[inline]
fn rem_assign(&mut self, other: BigDigit) { fn rem_assign(&mut self, other: u32) {
self.data %= other; self.data %= other;
if self.data.is_zero() { if self.data.is_zero() {
self.sign = NoSign; self.sign = NoSign;
@ -1590,7 +1859,7 @@ impl RemAssign<BigDigit> for BigInt {
} }
} }
impl Rem<BigInt> for BigDigit { impl Rem<BigInt> for u32 {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
@ -1599,18 +1868,18 @@ impl Rem<BigInt> for BigDigit {
} }
} }
impl Rem<DoubleBigDigit> for BigInt { impl Rem<u64> for BigInt {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
fn rem(self, other: DoubleBigDigit) -> BigInt { fn rem(self, other: u64) -> BigInt {
BigInt::from_biguint(self.sign, self.data % other) BigInt::from_biguint(self.sign, self.data % other)
} }
} }
impl RemAssign<DoubleBigDigit> for BigInt { impl RemAssign<u64> for BigInt {
#[inline] #[inline]
fn rem_assign(&mut self, other: DoubleBigDigit) { fn rem_assign(&mut self, other: u64) {
self.data %= other; self.data %= other;
if self.data.is_zero() { if self.data.is_zero() {
self.sign = NoSign; self.sign = NoSign;
@ -1618,7 +1887,38 @@ impl RemAssign<DoubleBigDigit> for BigInt {
} }
} }
impl Rem<BigInt> for DoubleBigDigit { impl Rem<BigInt> for u64 {
type Output = BigInt;
#[inline]
fn rem(self, other: BigInt) -> BigInt {
BigInt::from_biguint(Plus, self % other.data)
}
}
#[cfg(has_i128)]
impl Rem<u128> 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<u128> 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<BigInt> for u128 {
type Output = BigInt; type Output = BigInt;
#[inline] #[inline]
@ -1629,6 +1929,8 @@ impl Rem<BigInt> for DoubleBigDigit {
forward_all_scalar_binop_to_val_val!(impl Rem<i32> for BigInt, rem); forward_all_scalar_binop_to_val_val!(impl Rem<i32> for BigInt, rem);
forward_all_scalar_binop_to_val_val!(impl Rem<i64> for BigInt, rem); forward_all_scalar_binop_to_val_val!(impl Rem<i64> for BigInt, rem);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val!(impl Rem<i128> for BigInt, rem);
impl Rem<i32> for BigInt { impl Rem<i32> for BigInt {
type Output = BigInt; type Output = BigInt;
@ -1704,6 +2006,44 @@ impl Rem<BigInt> for i64 {
} }
} }
#[cfg(has_i128)]
impl Rem<i128> 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<i128> 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<BigInt> 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 { impl Neg for BigInt {
type Output = BigInt; type Output = BigInt;

View File

@ -24,7 +24,7 @@ use traits::{
ToPrimitive, Unsigned, Zero, ToPrimitive, Unsigned, Zero,
}; };
use big_digit::{self, BigDigit, DoubleBigDigit}; use big_digit::{self, BigDigit};
#[path = "algorithms.rs"] #[path = "algorithms.rs"]
mod algorithms; mod algorithms;
@ -518,27 +518,30 @@ impl<'a> AddAssign<&'a BigUint> for BigUint {
promote_unsigned_scalars!(impl Add for BigUint, add); promote_unsigned_scalars!(impl Add for BigUint, add);
promote_unsigned_scalars_assign!(impl AddAssign for BigUint, add_assign); promote_unsigned_scalars_assign!(impl AddAssign for BigUint, add_assign);
forward_all_scalar_binop_to_val_val_commutative!(impl Add<BigDigit> for BigUint, add); forward_all_scalar_binop_to_val_val_commutative!(impl Add<u32> for BigUint, add);
forward_all_scalar_binop_to_val_val_commutative!(impl Add<DoubleBigDigit> for BigUint, add); forward_all_scalar_binop_to_val_val_commutative!(impl Add<u64> for BigUint, add);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val_commutative!(impl Add<u128> for BigUint, add);
impl Add<BigDigit> for BigUint { impl Add<u32> for BigUint {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
fn add(mut self, other: BigDigit) -> BigUint { fn add(mut self, other: u32) -> BigUint {
self += other; self += other;
self self
} }
} }
impl AddAssign<BigDigit> for BigUint {
impl AddAssign<u32> for BigUint {
#[inline] #[inline]
fn add_assign(&mut self, other: BigDigit) { fn add_assign(&mut self, other: u32) {
if other != 0 { if other != 0 {
if self.data.len() == 0 { if self.data.len() == 0 {
self.data.push(0); self.data.push(0);
} }
let carry = __add2(&mut self.data, &[other]); let carry = __add2(&mut self.data, &[other as BigDigit]);
if carry != 0 { if carry != 0 {
self.data.push(carry); self.data.push(carry);
} }
@ -546,18 +549,19 @@ impl AddAssign<BigDigit> for BigUint {
} }
} }
impl Add<DoubleBigDigit> for BigUint { impl Add<u64> for BigUint {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
fn add(mut self, other: DoubleBigDigit) -> BigUint { fn add(mut self, other: u64) -> BigUint {
self += other; self += other;
self self
} }
} }
impl AddAssign<DoubleBigDigit> for BigUint {
impl AddAssign<u64> for BigUint {
#[inline] #[inline]
fn add_assign(&mut self, other: DoubleBigDigit) { fn add_assign(&mut self, other: u64) {
let (hi, lo) = big_digit::from_doublebigdigit(other); let (hi, lo) = big_digit::from_doublebigdigit(other);
if hi == 0 { if hi == 0 {
*self += lo; *self += lo;
@ -574,6 +578,44 @@ impl AddAssign<DoubleBigDigit> for BigUint {
} }
} }
#[cfg(has_i128)]
impl Add<u128> for BigUint {
type Output = BigUint;
#[inline]
fn add(mut self, other: u128) -> BigUint {
self += other;
self
}
}
#[cfg(has_i128)]
impl AddAssign<u128> 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_val_val_binop!(impl Sub for BigUint, sub);
forward_ref_ref_binop!(impl Sub for BigUint, sub); forward_ref_ref_binop!(impl Sub for BigUint, sub);
forward_val_assign!(impl SubAssign for BigUint, sub_assign); forward_val_assign!(impl SubAssign for BigUint, sub_assign);
@ -613,57 +655,61 @@ impl<'a> Sub<BigUint> for &'a BigUint {
promote_unsigned_scalars!(impl Sub for BigUint, sub); promote_unsigned_scalars!(impl Sub for BigUint, sub);
promote_unsigned_scalars_assign!(impl SubAssign for BigUint, sub_assign); promote_unsigned_scalars_assign!(impl SubAssign for BigUint, sub_assign);
forward_all_scalar_binop_to_val_val!(impl Sub<BigDigit> for BigUint, sub); forward_all_scalar_binop_to_val_val!(impl Sub<u32> for BigUint, sub);
forward_all_scalar_binop_to_val_val!(impl Sub<DoubleBigDigit> for BigUint, sub); forward_all_scalar_binop_to_val_val!(impl Sub<u64> for BigUint, sub);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val!(impl Sub<u128> for BigUint, sub);
impl Sub<BigDigit> for BigUint { impl Sub<u32> for BigUint {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
fn sub(mut self, other: BigDigit) -> BigUint { fn sub(mut self, other: u32) -> BigUint {
self -= other; self -= other;
self self
} }
} }
impl SubAssign<BigDigit> for BigUint { impl SubAssign<u32> for BigUint {
fn sub_assign(&mut self, other: BigDigit) { fn sub_assign(&mut self, other: u32) {
sub2(&mut self.data[..], &[other]); sub2(&mut self.data[..], &[other as BigDigit]);
self.normalize(); self.normalize();
} }
} }
impl Sub<BigUint> for BigDigit { impl Sub<BigUint> for u32 {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
fn sub(self, mut other: BigUint) -> BigUint { fn sub(self, mut other: BigUint) -> BigUint {
if other.data.len() == 0 { if other.data.len() == 0 {
other.data.push(self); other.data.push(self as BigDigit);
} else { } else {
sub2rev(&[self], &mut other.data[..]); sub2rev(&[self as BigDigit], &mut other.data[..]);
} }
other.normalized() other.normalized()
} }
} }
impl Sub<DoubleBigDigit> for BigUint { impl Sub<u64> for BigUint {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
fn sub(mut self, other: DoubleBigDigit) -> BigUint { fn sub(mut self, other: u64) -> BigUint {
self -= other; self -= other;
self self
} }
} }
impl SubAssign<DoubleBigDigit> for BigUint {
fn sub_assign(&mut self, other: DoubleBigDigit) { impl SubAssign<u64> for BigUint {
#[inline]
fn sub_assign(&mut self, other: u64) {
let (hi, lo) = big_digit::from_doublebigdigit(other); let (hi, lo) = big_digit::from_doublebigdigit(other);
sub2(&mut self.data[..], &[lo, hi]); sub2(&mut self.data[..], &[lo, hi]);
self.normalize(); self.normalize();
} }
} }
impl Sub<BigUint> for DoubleBigDigit { impl Sub<BigUint> for u64 {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
@ -678,6 +724,41 @@ impl Sub<BigUint> for DoubleBigDigit {
} }
} }
#[cfg(has_i128)]
impl Sub<u128> for BigUint {
type Output = BigUint;
#[inline]
fn sub(mut self, other: u128) -> BigUint {
self -= other;
self
}
}
#[cfg(has_i128)]
impl SubAssign<u128> 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<BigUint> 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_all_binop_to_ref_ref!(impl Mul for BigUint, mul);
forward_val_assign!(impl MulAssign for BigUint, mul_assign); 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!(impl Mul for BigUint, mul);
promote_unsigned_scalars_assign!(impl MulAssign for BigUint, mul_assign); promote_unsigned_scalars_assign!(impl MulAssign for BigUint, mul_assign);
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<BigDigit> for BigUint, mul); forward_all_scalar_binop_to_val_val_commutative!(impl Mul<u32> for BigUint, mul);
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<DoubleBigDigit> for BigUint, mul); forward_all_scalar_binop_to_val_val_commutative!(impl Mul<u64> for BigUint, mul);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<u128> for BigUint, mul);
impl Mul<BigDigit> for BigUint { impl Mul<u32> for BigUint {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
fn mul(mut self, other: BigDigit) -> BigUint { fn mul(mut self, other: u32) -> BigUint {
self *= other; self *= other;
self self
} }
} }
impl MulAssign<BigDigit> for BigUint { impl MulAssign<u32> for BigUint {
#[inline] #[inline]
fn mul_assign(&mut self, other: BigDigit) { fn mul_assign(&mut self, other: u32) {
if other == 0 { if other == 0 {
self.data.clear(); self.data.clear();
} else { } else {
let carry = scalar_mul(&mut self.data[..], other); let carry = scalar_mul(&mut self.data[..], other as BigDigit);
if carry != 0 { if carry != 0 {
self.data.push(carry); self.data.push(carry);
} }
@ -724,21 +807,21 @@ impl MulAssign<BigDigit> for BigUint {
} }
} }
impl Mul<DoubleBigDigit> for BigUint { impl Mul<u64> for BigUint {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
fn mul(mut self, other: DoubleBigDigit) -> BigUint { fn mul(mut self, other: u64) -> BigUint {
self *= other; self *= other;
self self
} }
} }
impl MulAssign<DoubleBigDigit> for BigUint { impl MulAssign<u64> for BigUint {
#[inline] #[inline]
fn mul_assign(&mut self, other: DoubleBigDigit) { fn mul_assign(&mut self, other: u64) {
if other == 0 { if other == 0 {
self.data.clear(); self.data.clear();
} else if other <= BigDigit::max_value() as DoubleBigDigit { } else if other <= BigDigit::max_value() as u64 {
*self *= other as BigDigit *self *= other as BigDigit
} else { } else {
let (hi, lo) = big_digit::from_doublebigdigit(other); let (hi, lo) = big_digit::from_doublebigdigit(other);
@ -747,6 +830,31 @@ impl MulAssign<DoubleBigDigit> for BigUint {
} }
} }
#[cfg(has_i128)]
impl Mul<u128> for BigUint {
type Output = BigUint;
#[inline]
fn mul(mut self, other: u128) -> BigUint {
self *= other;
self
}
}
#[cfg(has_i128)]
impl MulAssign<u128> 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_all_binop_to_ref_ref!(impl Div for BigUint, div);
forward_val_assign!(impl DivAssign for BigUint, div_assign); 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!(impl Div for BigUint, div);
promote_unsigned_scalars_assign!(impl DivAssign for BigUint, div_assign); promote_unsigned_scalars_assign!(impl DivAssign for BigUint, div_assign);
forward_all_scalar_binop_to_val_val!(impl Div<BigDigit> for BigUint, div); forward_all_scalar_binop_to_val_val!(impl Div<u32> for BigUint, div);
forward_all_scalar_binop_to_val_val!(impl Div<DoubleBigDigit> for BigUint, div); forward_all_scalar_binop_to_val_val!(impl Div<u64> for BigUint, div);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val!(impl Div<u128> for BigUint, div);
impl Div<BigDigit> for BigUint { impl Div<u32> for BigUint {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
fn div(self, other: BigDigit) -> BigUint { fn div(self, other: u32) -> BigUint {
let (q, _) = div_rem_digit(self, other); let (q, _) = div_rem_digit(self, other as BigDigit);
q q
} }
} }
impl DivAssign<BigDigit> for BigUint { impl DivAssign<u32> for BigUint {
#[inline] #[inline]
fn div_assign(&mut self, other: BigDigit) { fn div_assign(&mut self, other: u32) {
*self = &*self / other; *self = &*self / other;
} }
} }
impl Div<BigUint> for BigDigit { impl Div<BigUint> for u32 {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
fn div(self, other: BigUint) -> BigUint { fn div(self, other: BigUint) -> BigUint {
match other.data.len() { match other.data.len() {
0 => panic!(), 0 => panic!(),
1 => From::from(self / other.data[0]), 1 => From::from(self as BigDigit / other.data[0]),
_ => Zero::zero(), _ => Zero::zero(),
} }
} }
} }
impl Div<DoubleBigDigit> for BigUint { impl Div<u64> for BigUint {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
fn div(self, other: DoubleBigDigit) -> BigUint { fn div(self, other: u64) -> BigUint {
let (q, _) = self.div_rem(&From::from(other)); let (q, _) = self.div_rem(&From::from(other));
q q
} }
} }
impl DivAssign<DoubleBigDigit> for BigUint { impl DivAssign<u64> for BigUint {
#[inline] #[inline]
fn div_assign(&mut self, other: DoubleBigDigit) { fn div_assign(&mut self, other: u64) {
*self = &*self / other; *self = &*self / other;
} }
} }
impl Div<BigUint> for DoubleBigDigit { impl Div<BigUint> for u64 {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
@ -830,6 +940,45 @@ impl Div<BigUint> for DoubleBigDigit {
} }
} }
#[cfg(has_i128)]
impl Div<u128> 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<u128> for BigUint {
#[inline]
fn div_assign(&mut self, other: u128) {
*self = &*self / other;
}
}
#[cfg(has_i128)]
impl Div<BigUint> 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_all_binop_to_ref_ref!(impl Rem for BigUint, rem);
forward_val_assign!(impl RemAssign for BigUint, rem_assign); 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!(impl Rem for BigUint, rem);
promote_unsigned_scalars_assign!(impl RemAssign for BigUint, rem_assign); promote_unsigned_scalars_assign!(impl RemAssign for BigUint, rem_assign);
forward_all_scalar_binop_to_val_val!(impl Rem<BigDigit> for BigUint, rem); forward_all_scalar_binop_to_val_val!(impl Rem<u32> for BigUint, rem);
forward_all_scalar_binop_to_val_val!(impl Rem<DoubleBigDigit> for BigUint, rem); forward_all_scalar_binop_to_val_val!(impl Rem<u64> for BigUint, rem);
#[cfg(has_i128)]
forward_all_scalar_binop_to_val_val!(impl Rem<u128> for BigUint, rem);
impl Rem<BigDigit> for BigUint { impl Rem<u32> for BigUint {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
fn rem(self, other: BigDigit) -> BigUint { fn rem(self, other: u32) -> BigUint {
let (_, r) = div_rem_digit(self, other); let (_, r) = div_rem_digit(self, other as BigDigit);
From::from(r) From::from(r)
} }
} }
impl RemAssign<BigDigit> for BigUint { impl RemAssign<u32> for BigUint {
#[inline] #[inline]
fn rem_assign(&mut self, other: BigDigit) { fn rem_assign(&mut self, other: u32) {
*self = &*self % other; *self = &*self % other;
} }
} }
impl Rem<BigUint> for BigDigit { impl Rem<BigUint> for u32 {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
@ -896,34 +1047,67 @@ macro_rules! impl_rem_assign_scalar {
} }
} }
// we can scalar %= BigUint for any scalar, including signed types // 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!(usize, to_usize);
impl_rem_assign_scalar!(u64, to_u64); impl_rem_assign_scalar!(u64, to_u64);
impl_rem_assign_scalar!(u32, to_u32); impl_rem_assign_scalar!(u32, to_u32);
impl_rem_assign_scalar!(u16, to_u16); impl_rem_assign_scalar!(u16, to_u16);
impl_rem_assign_scalar!(u8, to_u8); 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!(isize, to_isize);
impl_rem_assign_scalar!(i64, to_i64); impl_rem_assign_scalar!(i64, to_i64);
impl_rem_assign_scalar!(i32, to_i32); impl_rem_assign_scalar!(i32, to_i32);
impl_rem_assign_scalar!(i16, to_i16); impl_rem_assign_scalar!(i16, to_i16);
impl_rem_assign_scalar!(i8, to_i8); impl_rem_assign_scalar!(i8, to_i8);
impl Rem<DoubleBigDigit> for BigUint { impl Rem<u64> for BigUint {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
fn rem(self, other: DoubleBigDigit) -> BigUint { fn rem(self, other: u64) -> BigUint {
let (_, r) = self.div_rem(&From::from(other)); let (_, r) = self.div_rem(&From::from(other));
r r
} }
} }
impl RemAssign<DoubleBigDigit> for BigUint { impl RemAssign<u64> for BigUint {
#[inline] #[inline]
fn rem_assign(&mut self, other: DoubleBigDigit) { fn rem_assign(&mut self, other: u64) {
*self = &*self % other; *self = &*self % other;
} }
} }
impl Rem<BigUint> for DoubleBigDigit { impl Rem<BigUint> for u64 {
type Output = BigUint;
#[inline]
fn rem(mut self, other: BigUint) -> BigUint {
self %= other;
From::from(self)
}
}
#[cfg(has_i128)]
impl Rem<u128> 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<u128> for BigUint {
#[inline]
fn rem_assign(&mut self, other: u128) {
*self = &*self % other;
}
}
#[cfg(has_i128)]
impl Rem<BigUint> for u128 {
type Output = BigUint; type Output = BigUint;
#[inline] #[inline]
@ -1247,10 +1431,10 @@ impl ToPrimitive for BigUint {
return None; return None;
} }
ret += (*i as u128) << bits; ret |= (*i as u128) << bits;
bits += big_digit::BITS; bits += big_digit::BITS;
} }
println!("{:?} -> {}", self, ret);
Some(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")] #[cfg(feature = "serde")]
impl serde::Serialize for BigUint { impl serde::Serialize for BigUint {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@ -2596,3 +2799,55 @@ fn test_assign_from_slice() {
check(&[0, 0, 1, 2, 0, 0], &[0, 0, 1, 2]); check(&[0, 0, 1, 2, 0, 0], &[0, 0, 1, 2]);
check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]); 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);
}
}

View File

@ -13,6 +13,7 @@ pub const SUM_TRIPLES: &'static [(&'static [u32], &'static [u32], &'static [u32]
(&[N1, N1], &[N1, N1], &[N2, N1, 1]), (&[N1, N1], &[N1, N1], &[N2, N1, 1]),
(&[1, 1, 1], &[N1, N1], &[0, 1, 2]), (&[1, 1, 1], &[N1, N1], &[0, 1, 2]),
(&[2, 2, 1], &[N1, N2], &[1, 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; pub const M: u32 = ::std::u32::MAX;

View File

@ -35,6 +35,7 @@ macro_rules! assert_scalar_op {
}; };
} }
#[cfg(not(has_i128))]
macro_rules! assert_unsigned_scalar_op { macro_rules! assert_unsigned_scalar_op {
($left:ident $op:tt $right:ident == $expected:expr) => { ($left:ident $op:tt $right:ident == $expected:expr) => {
assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize) 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 { macro_rules! assert_signed_scalar_op {
($left:ident $op:tt $right:ident == $expected:expr) => { ($left:ident $op:tt $right:ident == $expected:expr) => {
assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, 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); $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);
};
}